2013-07-30 13 views
9

Ich versuche eine abstrakte Klasse zu testen und Mockito initialisiert meine Membervariablen nicht. Hier ist ein einfaches Beispiel, um Ihnen mein Problem zu zeigen.Warum überspringt Mockito die Initialisierung der Membervariablen meiner abstrakten Klasse

Dies ist eine abstrakte Klasse, die ihr 'Feld' Mitglied initialisiert:

import java.util.ArrayList; 
import java.util.Collection; 

public abstract class Foo { 
    private final Collection field = new ArrayList(); 

    protected Foo() { 
     System.out.println("In constructor"); 
    } 

    public boolean isNull(Object o) { 
     field.add(o); 

     return o == null; 
    } 

    abstract void someAbstractMethod(); 
} 

Hier die Testklasse:

import org.junit.Assert; 
import org.junit.Test; 
import org.mockito.Mockito; 

public class FooTest { 
    @Test 
    public void testSomething() { 
     final Foo foo = Mockito.mock(Foo.class); 

     Mockito.when(foo.isNull(Mockito.anyObject())).thenCallRealMethod(); 

     Assert.assertFalse(foo.isNull("baaba")); 
    } 
} 

Wenn der Test wirft, weil die Variable ‚Feld ein NPE ausgeführt wird 'ist nicht initialisiert!

Was mache ich falsch?

+0

Die Verwendung von http://docs.mockito.googlecode.com/hg/org/mockito/stubbing/OngoingStubbing.html#thenCallRealMethod%28%29 wird nicht empfohlen. Was willst du testen? Wenn es die Implementierung einiger Methoden von Foo ist, dann erstellen Sie einfach eine Unterklasse. Verwenden Sie Mockito, wenn Sie Verhaltens- oder Stub-Methodenaufrufe verifizieren möchten. –

+0

Wie ich zu [@ david-wallace] (http://stackoverflow.com/users/1081110/david-wallace) gesagt habe, möchte ich die abstrakte Klasse testen. Meine Absicht, einen Mock zu verwenden, bestand darin, Kompilierungsfehler zu vermeiden, sollte sich die abstrakte Klasse oder eine ihrer Schnittstellen ändern. – Pigelvy

Antwort

4

Dies ist das erwartete Verhalten, wenn Sie etwas vortäuschen, was die erstellte Instanz vollständig simuliert, sodass es keinen Sinn macht, die Felder zu initialisieren, da das Verhalten standardmäßig ist.

Abgesehen davon können Felder von einem Konstruktor in konkreten oder abstrakten Klassen initialisiert werden, da die Mock-Instanziierung den Konstruktor umgeht, weil es einfach ein Spott ist, es ist noch irrationaler, sie zu initialisieren.

Der Versuch, die echte Methode aufzurufen, ist normalerweise falsch, wenn Mocks verwendet werden. Stattdessen sollte man das Verhalten des Mocks stubben.

Mockito.when(foo.isNull(Mockito.anyObject())).thenReturn(false); 
Assert.assertFalse(foo.isNull("baaba")); // assertion always passing 

Ich weiß nicht, Ihren konkreten Fall Anwendung, aber vielleicht wollen Sie eine partielle Mock, mit einem spy. Obwohl dies immer noch als schlechte Praxis angesehen wird, bedeutet dies normalerweise, dass Sie den Code neu strukturieren müssen, um Komposition zu verwenden.

+0

Ich erwartete, Mockito würde etwas tun, für das es nicht vorgesehen war. Wie in [@ David-Wallace] (http://stackoverflow.com/users/1081110/david-wallace) besprochen, werde ich in meinen Tests Dummy-Implementierungen erstellen, die ich beibehalten muss, wenn Methoden hinzugefügt/entfernt werden. Thx – Pigelvy

+0

Ist dies auch das erwartete Verhalten für statische Mitglieder? Ich habe versucht und Mockito benötigt statische Mitglieder initialisiert werden, sollte diese Initialisierung auch nicht richtig? – dushyantashu

+0

@dushyantashu statische Member werden vom Classloader initialisiert, wenn die Klasse geladen wird. Mockito ändert das nicht. – Brice

3

Sie scheinen sich über die Klasse lustig zu machen, die Sie tatsächlich testen möchten. Das ist nicht wirklich die Idee zu spotten. Du machst Klassen vor, die außerhalb des Testumfangs liegen, und lässt das, was du testet, unblockiert.

In diesem Fall sollten Sie wahrscheinlich nur eine Foo mit einer Dummy-Implementierung von erstellen und diese direkt testen. Keine Notwendigkeit für irgendwelche Spott, soweit ich sehen kann.

+0

In der Tat, ich möchte die abstrakte Klasse, die ich testen, verspotten, so dass die Tests nicht fehlschlagen, wenn eine neue abstrakte Methode zu dieser Klasse (oder einer ihrer Schnittstellen) hinzugefügt wird. Ist das wirklich eine schlechte Übung? – Pigelvy

+0

Ich bin nicht erfahren genug, um das Gesetz über das, was eine "schlechte Praxis" ist und was nicht, niederzulegen. Aber es fühlt sich eher an wie ein Meißel als Schraubenzieher. Es ist nicht das, wofür Mocks entworfen wurden.Mein Instinkt wäre es, beim Testen der eigenen Dummy-Implementierung zu bleiben und die neuen Methoden überall dort hinzuzufügen, wo sie benötigt werden. Ich schätze, es hängt davon ab, wie oft Sie der Klasse eine neue abstrakte Methode hinzufügen wollen - wenn es häufig vorkommt, dann trifft wahrscheinlich Brice's Refactoring zur Verwendung der Komposition zu. Die Antwort auf Ihre Frage ist jedoch, dass Mockito nie dazu gedacht war ... –

+0

... Felder in seinen Mocks zu initialisieren; jetzt mit diesem Wissen bewaffnet, gehen Sie voran und machen Sie Ihre Tests in der für Sie am besten geeigneten Weise. –

Verwandte Themen