2015-10-14 25 views
14

Così ho iniziato a scrivere test per il nostro progetto Java-Spring.Mockito - NullpointerException when stubbing Metodo

Quello che uso è JUnit e Mockito. Si dice che quando uso l'opzione when() ... thenReturn() posso simulare servizi, senza simularli o altro. Quindi quello che voglio fare è, per impostare:

when(classIwantToTest.object.get().methodWhichReturnsAList(input))thenReturn(ListcreatedInsideTheTestClass) 

Ma non importa che quando clausola che faccio, ho sempre ottenere un NullPointerException, che ovviamente ha un senso, perché in ingresso è nullo.

anche quando cerco di prendere in giro un altro metodo da un oggetto:

when(object.method()).thenReturn(true) 

Lì ho anche ottenere un Nullpointer, perché il metodo ha bisogno di una variabile, che non è impostato.

Ma voglio usare when() .. thenReturn() per aggirare la creazione di questa variabile e così via. Voglio solo assicurarmi che, se una classe chiama questo metodo, non importa cosa, restituisce true o la lista sopra.

È un malinteso fondamentalmente da parte mia, o c'è qualcos'altro che non va?

Codice:

public class classIWantToTest implements classIWantToTestFacade{ 
     @Autowired 
     private SomeService myService; 

     @Override 
     public Optional<OutputData> getInformations(final InputData inputData) { 
      final Optional<OutputData> data = myService.getListWithData(inputData); 
      if (data.isPresent()) { 
       final List<ItemData> allData = data.get().getItemDatas(); 
        //do something with the data and allData 
       return data; 
      } 

      return Optional.absent(); 
     } 
} 

Ed ecco la mia classe di test:

public class Test { 

    private InputData inputdata; 

    private ClassUnderTest classUnderTest; 

    final List<ItemData> allData = new ArrayList<ItemData>(); 

    @Mock 
    private DeliveryItemData item1; 

    @Mock 
    private DeliveryItemData item2; 



    @Mock 
    private SomeService myService; 


    @Before 
    public void setUp() throws Exception { 
     classUnderTest = new ClassUnderTest(); 
     myService = mock(myService.class); 
     classUnderTest.setService(myService); 
     item1 = mock(DeliveryItemData.class); 
     item2 = mock(DeliveryItemData.class); 

    } 


    @Test 
    public void test_sort() { 
     createData(); 
     when(myService.getListWithData(inputdata).get().getItemDatas()); 

     when(item1.hasSomething()).thenReturn(true); 
     when(item2.hasSomething()).thenReturn(false); 

    } 

    public void createData() { 
     item1.setSomeValue("val"); 
     item2.setSomeOtherValue("test"); 

     item2.setSomeValue("val"); 
     item2.setSomeOtherValue("value"); 

     allData.add(item1); 
     allData.add(item2); 


} 
+2

l'oggetto in quando() deve essere un mock creato da Mockito.mock(), non funziona per oggetti reali creati manualmente - non è sicuro se questo è il tuo problema, dal momento che non riesco a capire dove si trova il tuo problema. .. – Nadir

+1

Si prega di inviare un po 'di codice. –

+1

Sembra che 'classIwantToTest.object.get()' result non è un mock, o che 'get()' sta restituendo null. Ma per favore pubblica il tuo codice, mostra il tuo test e inizializza i tuoi mock. – vikingsteve

risposta

20

Il valore di ritorno di default di metodi che non hai ancora sradicate è false per i metodi booleani, una collezione vuota o mappa per metodi che restituiscono collezioni o mappe e null in caso contrario.

Questo vale anche per le chiamate di metodo entro when(...). Nel tuo esempio, when(myService.getListWithData(inputData).get()) causerà una eccezione NullPointerException perché myService.getListWithData(inputData) è null - non è stato precedentemente eseguito lo stub.

Un'opzione è creare mock per tutti i valori di ritorno intermedi e stubli prima dell'uso. Per esempio:

ListWithData listWithData = mock(ListWithData.class); 
when(listWithData.get()).thenReturn(item1); 
when(myService.getListWithData()).thenReturn(listWithData); 

Oppure, in alternativa, è possibile specificare una diversa risposta di default quando si crea un finto, per rendere metodi restituiscono una nuova finta invece di null: RETURNS_DEEP_STUBS

SomeService myService = mock(SomeService.class, Mockito.RETURNS_DEEP_STUBS); 
when(myService.getListWithData().get()).thenReturn(item1); 

Si consiglia di leggere il Javadoc di Mockito.RETURNS_DEEP_STUBS che spiega questo in modo più dettagliato e ha anche alcuni avvertimenti sul suo utilizzo.

Spero che questo aiuti. Basta notare che il codice di esempio sembra avere più problemi, come asser o verificare asserzioni e setter di chiamata su mock (che non ha alcun effetto).

13

Ho avuto lo stesso problema e il mio problema era semplicemente che non avevo annotato correttamente la classe usando @RunWith. Nel tuo esempio, assicurarsi di avere:

@RunWith(MockitoJUnitRunner.class) 
public class Test { 
... 

Una volta che ho fatto, i NullPointerExceptions scomparsi.

+0

Ho ottenuto il puntatore nullo bcoz di @RunWith (PowerMockRunner.class), invece di quello modificato in @RunWith (MockitoJUnitRunner.class). –

27

Avevo questo problema e il mio problema era che stavo chiamando il mio metodo con any() invece di anyInt(). Così ho avuto:

doAnswer(...).with(myMockObject).thisFuncTakesAnInt(any()) 

e ho dovuto cambiare a:

doAnswer(...).with(myMockObject).thisFuncTakesAnInt(anyInt()) 

Non ho idea perché questo prodotto un NullPointerException. Forse questo aiuterà la prossima povera anima.

+2

Questo ha funzionato per me. Lasciando questo commento per la prossima povera anima. –

+4

I Matchers non funzionano per i primitivi, quindi se l'argomento è un primitivo avrai bisogno di anyChar/Int/Boolean ecc. – micah

+3

Come prossima povera anima, hai i miei ringraziamenti e +1. – Mac

0
@RunWith(MockitoJUnitRunner.class)//PowerMockRunner.class 

@PrepareForTest({UpdateUtil.class,Log.class,SharedPreferences.class,SharedPreferences.Editor.class}) 
public class InstallationTest extends TestCase{ 
@Mock 
Context mockContext; 
@Mock 
SharedPreferences mSharedPreferences; 
@Mock 
SharedPreferences.Editor mSharedPreferenceEdtor; 

@Before 
public void setUp() throws Exception 
{ 
//  mockContext = Mockito.mock(Context.class); 
//  mSharedPreferences = Mockito.mock(SharedPreferences.class); 
//  mSharedPreferenceEdtor = Mockito.mock(SharedPreferences.Editor.class); 
    when(mockContext.getSharedPreferences(Mockito.anyString(),Mockito.anyInt())).thenReturn(mSharedPreferences); 
    when(mSharedPreferences.edit()).thenReturn(mSharedPreferenceEdtor); 
    when(mSharedPreferenceEdtor.remove(Mockito.anyString())).thenReturn(mSharedPreferenceEdtor); 
    when(mSharedPreferenceEdtor.putString(Mockito.anyString(),Mockito.anyString())).thenReturn(mSharedPreferenceEdtor); 
} 

@Test 
public void deletePrefernces_test() throws Exception { 

} 
} 

Tutti i codici di cui sopra commentate non sono necessari (mockContext = Mockito.mock (Context.class);) se si utilizza @Mock annotazione di Context mockContext; Ma funzionerà solo se si utilizza @RunWith (MockitoJUnitRunner.class). Come per Mockito puoi creare oggetti mock usando @Mock o Mockito.mock (Context.class);,

Ho ottenuto il puntatore nullo bcoz di @RunWith (PowerMockRunner.class), invece di quello modificato in @RunWith (MockitoJUnitRunner.class).

1

caso d'angolo:
Se stai usando Scala e si tenta di creare un any matcher su una classe valore, si otterrà un NPE inutile.

Quindi, dato case class ValueClass(value: Int) extends AnyVal, ciò che si vuole fare è ValueClass(anyInt) invece di any[ValueClass]

when(mock.someMethod(ValueClass(anyInt))).thenAnswer { 
    ... 
    val v = ValueClass(invocation.getArguments()(0).asInstanceOf[Int]) 
    ... 
} 

Quest'altra SO question è più specificamente di questo, ma si sarebbe mancato quando non si conosce il problema è con classi di valore.