2015-08-17 10 views
6

Ich habe eine Klasse Dummy. Ich spritze 3 Variablen. Jedoch ist einer von ihnen nicht injizierbar, weil es eine Schnittstelle ist. Also injiziere ich ein Objekt, dessen Methoden den benötigten Typ zurückgeben.Warum gibt meine Stub-Methode null zurück?

Class Dummy 
{ 
    private final Class1 class1; 
    private final Class2 class2 
    private final Interface1 interface1; 

    @Inject 
    Dummy(Class1 class1, Class2 class2, HelperClass helperclass) 
    { 
     this.class1 = class1; 
     this.class2 = class2; 
     this.interface1 = helperclass.somefunction(); 
    } 
} 

Die HelperClass ‚s somefunction gibt eine Instanz Interface1.

Dies ist mein Test:

@RunWith(MockitoJUnitRunner.class) 
Class DummyTest 
{ 
    @Mock 
    private Class1 class1; 

    @Mock 
    private Class2 class2; 

    @Mock 
    private HelperClass helperclass; 

    @InjectMocks 
    private Dummy dummy; 

    @Before 
    public void start() 
    { 
    Interface1 mockInterface = mock(Interface1.class); 
    when(helperclass.somefunction()).thenReturn(mockInterface); 
    } 
    @Test 
    public void test() 
    { 
    // etc... 
    } 
} 

jedoch interface1 null ist, wenn ich den Test ausführen. Was mache ich falsch?

+0

Ich nehme an, Interface1 ist eine Klasse, die Interfaces implementieren, oder? – Koitoer

+0

@Koitoer Keine Schnittstelle1 ist eine 'Schnittstelle'. Nicht Implementierung. Es ist analog zu "List" nicht "ArrayList" – user7

Antwort

6

@InjectMocks passiert vor der @Before Annotation.

Aus diesem Grund (und other reasons) empfehle ich nicht @InjectMocks überhaupt zu verwenden; Erstellen Sie einfach Ihre SUT Klasse in der @Before Methode mit einem echten Konstruktor.

Diese Reihenfolge ist offensichtlich, wenn Sie Ihrer Testklasse einige Druckanweisungen hinzufügen. Ich habe alle Class1 und Class2 Sachen entfernt, da es nicht relevant ist. Sehen Sie diesen Code ausführen:

@RunWith(MockitoJUnitRunner.class) 
public class DummyTest { 
    @Mock 
    private HelperClass helperclass; 

    @InjectMocks 
    private Dummy dummy; 

    @Before 
    public void start() 
    { 
    System.out.println("In @Before!"); 
    Interface1 mockInterface = mock(Interface1.class); 
    when(helperclass.somefunction()).thenReturn(mockInterface); 
    } 

    @Test 
    public void test() 
    { 
    System.out.println("In @Test!"); 
    } 

    public static class Dummy { 
    public final Interface1 interface1; 
    public final HelperClass helperclass; 

    @Inject 
    Dummy(HelperClass helperclass) 
    { 
    System.out.println("In dummy constructor!"); 
     this.interface1 = helperclass.somefunction(); 
     this.helperclass = helperclass; 
    } 
} 

    private static class HelperClass { 
    Interface1 somefunction() { 
     return new Interface1() {}; 
    } 
    } 

    private static interface Interface1 { 

    } 
} 

Ausgang:

In dummy constructor! 
In @Before! 
In @Test! 

Wenn Sie darauf bestehen, es mit @Mock tun und @InjectMocks, Sie könnten versuchen, die answer Argument statt:

@Mock(answer=Answers.RETURNS_MOCKS) 

wird helperclass.somemethod() einen Schein stattzurückgeben.


Ehrlich gesagt ist es nicht verwunderlich, dass es so funktioniert. Die Autoren von Mockito wirklich nicht, wie teilweise Mocks/Stubs und ausdrücklich sagen, so in their documentation:

Wie üblich Sie gehen die partielle Mock Warnung lesen: Objektorientierte Programmierung ist weniger Komplexität der Bekämpfung durch Dividieren die Komplexität in separate, spezifische SRPy-Objekte. Wie passt partieller Schein in dieses Paradigma? Nun, es ist einfach nicht ... Partial Mock bedeutet in der Regel, dass die Komplexität auf eine andere Methode auf demselben Objekt verschoben wurde. In den meisten Fällen ist dies nicht die Art und Weise, wie Sie Ihre Anwendung entwerfen möchten.

Es gibt jedoch seltene Fälle, in denen partielle Mocks praktisch sind: Umgang mit Code, den man nicht leicht ändern kann (Interfaces von Drittanbietern, vorläufiges Refactoring von Legacy-Code usw.) Ich würde jedoch keine partiellen Mocks für neue, Test- angetriebenen & gut gestalteten Code.

helperclass Rückkehr etwas anderes als null zu haben, ist eine partielle Mock, und deshalb werden sie es nicht mögen.

+0

Danke für Ihre Erklärung .. Ich wünschte, ich könnte Ihre Antwort auch akzeptieren ... – user7

+0

@ user7 Sie können immer eine zuvor akzeptierte Antwort nicht akzeptieren, wenn Sie eine andere Antwort eine bessere Lösung bietet. – TylerH

+0

Gute Antwort und bessere Erklärung =) – Koitoer