2015-08-17 35 views
6

Ho una classe Dummy. Inietto 3 variabili. Tuttavia, uno di questi non è iniettabile perché è un'interfaccia. Quindi inietto un oggetto, uno dei cui metodi restituisce il tipo necessario.Perché il metodo stub restituisce null?

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(); 
    } 
} 

s' The HelperClasssomefunction restituisce un'istanza di Interface1.

Questa è la mia prova:

@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... 
    } 
} 

Tuttavia, interface1 è nullo quando si esegue il test. Che cosa sto facendo di sbagliato?

+0

Presumo che l'interfaccia1 è un clase che implementa de interfacce, giusto? – Koitoer

+0

@Koitoer Nessuna interfaccia1 è un'interfaccia '. Non implementazione. È analogo a 'List' not' ArrayList' – user7

risposta

6

@InjectMocks si verifica prima dell'annotazione @Before.

Per questo motivo (e other reasons), si consiglia di non utilizzare @InjectMocks; crea la tua classe SUT nel metodo @Before con un vero costruttore.

Questo ordine è evidente quando si aggiungono alcune istruzioni di stampa alla classe di test. Ho rimosso tutte le cose Class1 e Class2 perché non pertinenti. Vedere questo codice run:

@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 { 

    } 
} 

uscita:

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

Se ti ostini a farlo con @Mock e @InjectMocks, si potrebbe provare a utilizzare l'argomento answer invece:

@Mock(answer=Answers.RETURNS_MOCKS) 

renderà helperclass.somemethod() restituire una simulazione anziché null.


Onestamente, non sorprende che funzioni in questo modo. Gli autori di Mockito davvero non piace parziale Mocks/stub, ed esplicitamente dicono così in their documentation:

Come al solito si sta andando a leggere parziale avvertimento finto: programmazione orientata agli oggetti è più meno di affrontare la complessità dividendo la complessità in oggetti SRPy separati, specifici. Come si inserisce parzialmente il parto in questo paradigma? Beh, semplicemente non ... La simulazione parziale di solito significa che la complessità è stata spostata su un metodo diverso sullo stesso oggetto. Nella maggior parte dei casi, questo non è il modo in cui si desidera progettare la propria applicazione.

Tuttavia, ci sono rari casi in cui prende in giro parziali tornare utile: si tratta di codice non è possibile modificare facilmente (interfacce 3rd party, refactoring ad interim di codice legacy, ecc) Tuttavia, non vorrei usare mock parziali per il nuovo, test- pilotato & codice ben progettato.

Avere helperclass ritorno qualcosa di diverso da null è un finto parziali, e quindi non piacerà.

+0

Grazie per la tua spiegazione .. Vorrei poter accettare anche la tua risposta ... – user7

+0

@ user7 Puoi sempre annullare una risposta precedentemente accettata se senti che un'altra risposta fornisce una soluzione migliore. – TylerH

+0

Buona risposta e spiegazione migliore =) – Koitoer