2015-10-14 25 views
14

Also fing ich an, Tests für unser Java-Spring-Projekt zu schreiben.Mockito - NullpointerException wenn stubbing Methode

Was ich benutze ist JUnit und Mockito. Es wird gesagt, dass ich, wenn ich die Option when() ... thenReturn() verwende, Dienste simulieren kann, ohne sie zu simulieren. Also, was ich tun möchte, ist, zu setzen:

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

Aber egal was when-Klausel ich tun, habe ich immer eine Nullpointer, was natürlich Sinn macht, weil Eingang null ist.

Auch wenn ich versuche, eine andere Methode von einem Objekt zu verspotten:

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

Es bekomme ich auch eine Nullpointer, da das Verfahren eine Variable benötigt, die nicht festgelegt ist.

Aber ich möchte verwenden, wenn() .. thenReturn() um diese Variable zu erstellen und so weiter. Ich möchte nur sicherstellen, dass, wenn irgendeine Klasse diese Methode aufruft, egal was passiert, geben Sie einfach true oder die obige Liste zurück.

Ist es ein grundsätzliches Missverständnis von meiner Seite, oder stimmt etwas anderes nicht?

Code:

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

Und hier ist meine Testklasse:

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

Das Objekt in when() muss ein Mock sein, erstellt von Mockito.mock(), es funktioniert nicht für manuell erstellte reale Objekte - nicht sicher, ob das Ihr Problem ist, da ich nicht wirklich wo Ihr Problem ist. .. – Nadir

+1

Bitte poste etwas Code. –

+1

Es klingt wie 'classIwantToTest.object.get()' Ergebnis ist kein Mock, oder das 'get()' gibt null zurück. Aber bitte posten Sie Ihren Code, zeigen Sie Ihren Test und die Initialisierung Ihrer Mocks. – vikingsteve

Antwort

20

Der Standardrückgabewert von Methoden, die Sie noch nicht gerodet haben, ist false für boolean Methoden, eine leere Sammlung oder Karte für Methoden, die Sammlungen oder Karten zurückgeben, und null andernfalls.

Dies gilt auch für Methodenaufrufe innerhalb von when(...). In Ihrem Beispiel when(myService.getListWithData(inputData).get()) wird eine NullPointerException verursachen, weil myService.getListWithData(inputData)null ist - es wurde nicht vorher stubbed.

Eine Option besteht darin, Mocks für alle Zwischen-Rückgabewerte zu erstellen und diese vor der Verwendung auszugeben. Zum Beispiel:

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

Oder alternativ können Sie eine andere Standardantwort angeben, wenn ein Modell erstellen, machen Methoden eine neue Mock statt null zurück: RETURNS_DEEP_STUBS

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

Sie die Javadoc lesen sollten Mockito.RETURNS_DEEP_STUBS, die dies ausführlicher erklärt und auch einige Warnungen über seine Verwendung hat.

Ich hoffe, das hilft. Beachten Sie, dass Ihr Beispielcode anscheinend mehr Probleme hat, wie z. B. das Fehlen von Assert- oder Verify-Anweisungen und das Aufrufen von Settern auf Mocks (die keinen Effekt haben).

13

Ich hatte das gleiche Problem und mein Problem war einfach, dass ich die Klasse nicht richtig mit @RunWith kommentiert hatte. In Ihrem Beispiel, stellen Sie sicher, dass Sie haben:

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

Sobald ich das täte, die Nullpointerexceptions verschwunden.

+0

Ich habe null Pointer Bcoz von @ RunWith (PowerMockRunner.class), statt dass ich zu @ RunWith (MockitoJUnitRunner.class) geändert. –

27

Ich hatte dieses Problem und mein Problem war, dass ich meine Methode mit any() anstelle von anyInt() aufgerufen habe. Also musste ich:

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

und ich musste es ändern:

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

Ich habe keine Ahnung, warum das ein Nullpointer produziert. Vielleicht hilft das der nächsten armen Seele.

+2

Das hat bei mir funktioniert. Hinterlasse diesen Kommentar für die nächste arme Seele. –

+4

Matcher werden nicht für Primitive arbeiten, also wenn das Argument ein Primitiv ist, brauchst du den anyChar/Int/Boolean usw. – micah

+3

Als nächste arme Seele, du hast meinen Dank und +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 { 

} 
} 

Alle oben kommentierten Codes sind nicht erforderlich (mockContext = Mockito.mock (Context.class);) wenn Sie @Mock Annotation zu Context mockContext verwenden; Aber es funktioniert, wenn Sie nur @RunWith (MockitoJUnitRunner.class) verwenden. Wie bei Mockito können Sie Mock-Objekte erstellen, indem Sie entweder @Mock oder Mockito.mock (Context.class) verwenden;,

Ich habe null Pointer bcoz von @RunWith (PowerMockRunner.class), stattdessen habe ich zu @RunWith (MockitoJUnitRunner.class) geändert.

1

Corner Fall:
Wenn Sie Scala verwenden und Sie versuchen, ein any Matcher auf eine Wert Klasse erstellen, erhalten Sie eine wenig hilfreiche NPE zu bekommen.

So case class ValueClass(value: Int) extends AnyVal gegeben, was Sie wollen, ist ValueClass(anyInt) statt any[ValueClass]

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

Diese andere SO question insbesondere darüber, aber man würde es vermissen, wenn Sie nicht wissen, ist das Problem mit Wertklassen.