web-dev-qa-db-fra.com

Mockito - NullpointerException lors de la méthode stubbing

J'ai donc commencé à écrire des tests pour notre projet Java-Spring-. 

Ce que j'utilise, c'est JUnit et Mockito. On dit que lorsque j'utilise l'option when () ... thenReturn (), je peux me moquer des services, sans les simuler. Donc ce que je veux faire est de définir:

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

Mais peu importe la clause when que je fais, j'obtiens toujours une exception NullpointerException, ce qui est logique, car l'entrée est nulle. 

Aussi, lorsque j'essaie de me moquer d'une autre méthode à partir d'un objet: 

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

Là aussi, j'obtiens un Nullpointer, car la méthode a besoin d'une variable, qui n'est pas définie. 

Mais je veux utiliser when () .. thenReturn () pour contourner la création de cette variable et ainsi de suite. Je veux juste m'assurer que, si une classe appelle cette méthode, alors, quoi qu'il arrive, retourne juste true ou la liste ci-dessus.

Est-ce fondamentalement un malentendu de ma part, ou y a-t-il autre chose qui ne va pas?

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

Et voici ma classe de 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);


}
27
user5417542

La valeur renvoyée par défaut des méthodes que vous n'avez pas encore modifiées est false pour les méthodes booléennes, une collection vide ou une carte pour les méthodes renvoyant des collections ou des cartes et null sinon.

Ceci s'applique également aux appels de méthode dans when(...). Dans votre exemple, when(myService.getListWithData(inputData).get()) provoquera une exception NullPointerException car myService.getListWithData(inputData) est null - elle n’a pas été stubée auparavant.

Une option est de créer des simulacres pour toutes les valeurs de retour intermédiaires et de les remplacer avant utilisation. Par exemple:

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

Ou bien, vous pouvez spécifier une réponse par défaut différente lors de la création d'une maquette, pour que les méthodes renvoient une nouvelle maquette au lieu de null: RETURNS_DEEP_STUBS

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

Vous devriez lire la Javadoc de Mockito.RETURNS_DEEP_STUBS qui explique cela plus en détail et qui contient également des avertissements sur son utilisation.

J'espère que ça aide. Notez simplement que votre code d'exemple semble avoir plus de problèmes, tels que des déclarations d'assertion ou de vérification manquantes et l'appel des modificateurs sur des répliques (ce qui n'a aucun effet).

34
ahu

J'avais ce problème et mon problème était que j'appelais ma méthode avec any() au lieu de anyInt(). Alors j'ai eu:

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

et j'ai dû le changer pour:

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

Je ne sais pas pourquoi cela a généré une NullPointerException. Peut-être que cela aidera la prochaine pauvre âme.

68

J'avais le même problème et mon problème était simplement que je n'avais pas correctement annoté la classe en utilisant @RunWith. Dans votre exemple, assurez-vous que vous avez:

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

Une fois que j'ai fait cela, les NullPointerExceptions ont disparu.

31
Ed Webb

Pour moi, la raison pour laquelle je me suis procuré NPE est que j’utilisais Mockito.any() pour me moquer des primitives. J'ai trouvé qu'en passant à la variante correcte de mockito, on éliminait les erreurs.

Par exemple, pour simuler une fonction qui prend une primitive long en tant que paramètre, au lieu d'utiliser any(), vous devez être plus spécifique et la remplacer par any(Long.class) ou Mockito.anyLong().

J'espère que ça aide quelqu'un.

4
smac89

Affaire de coin:
Si vous utilisez Scala et que vous essayez de créer un adaptateur any sur une classe value, vous obtiendrez un NPE inutile.

Donc, étant donné case class ValueClass(value: Int) extends AnyVal, ce que vous voulez faire est ValueClass(anyInt) au lieu de any[ValueClass] 

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

Cette autre SO question traite plus précisément de cela, mais vous la manqueriez si vous ne saviez pas que le problème concerne les classes de valeur.

3
Vituel

Pour les futurs lecteurs, une autre cause de NPE lorsqu’on utilise des simulacres est l’oubli initial des simulacres comme suit:

@Mock
SomeMock someMock;

@InjectMocks
SomeService someService;

@Before
public void setup(){
    MockitoAnnotations.initMocks(this); //without this you will get NPE
}

@Test
public void someTest(){
    Mockito.when(someMock.someMethod()).thenReturn("some result");
   // ...
}
2
Tal Joffe
@RunWith(MockitoJUnitRunner.class) //(OR) 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 deletePreferencesTest() throws Exception {

 }
}

Tous les codes commentés ci-dessus ne sont pas requis {mockContext = Mockito.mock(Context.class);}, Si vous utilisez @Mock Annotation à Context mockContext; 

@Mock 
Context mockContext; 

Mais cela fonctionnera si vous utilisez @RunWith (MockitoJUnitRunner.class) only. Selon Mockito, vous pouvez créer un objet fictif en utilisant @Mock ou Mockito.mock (Context.class).

J'ai eu NullpointerException à cause de l'utilisation de @RunWith (PowerMockRunner.class). Au lieu de cela, j'ai changé en @RunWith (MockitoJUnitRunner.class).

1
anand krish

face au même problème, la solution qui a fonctionné pour moi:

Au lieu de se moquer de l'interface de service, j'ai utilisé @InjectMocks pour se moquer de l'implémentation du service:

@InjectMocks
private exampleServiceImpl exampleServiceMock;

au lieu de :

@Mock
private exampleService exampleServiceMock;
0

Dans mon cas, j'ai raté ajouter d'abord 

PowerMockito.spy(ClassWhichNeedToBeStaticMocked.class);

donc cela peut être utile à quelqu'un qui voit une telle erreur

Java.lang.NullPointerException
    at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing(PowerMockitoStubberImpl.Java:67)
    at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.Java:42)
    at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.Java:112)
0
Serhii Bohutskyi

Aucune de ces réponses n'a fonctionné pour moi. Cette réponse ne résout pas le problème d'OP, mais comme cet article est le seul à apparaître sur Google, je partage ma réponse ici.

Je suis tombé sur ce problème lors de l'écriture de tests unitaires pour Android. Le problème était que l'activité que je testais étendait AppCompatActivity au lieu de Activity. Pour résoudre ce problème, j'ai pu simplement remplacer AppCompatActivity par Activity car je n'en avais pas vraiment besoin. Ce n'est peut-être pas une solution viable pour tout le monde, mais espérons que connaître la cause fondamentale aidera quelqu'un. 

0
mindreader

Ed Webb's answer m'a aidé dans mon cas. Et au lieu de cela, vous pouvez également essayer d'ajouter 

  @Rule public Mocks mocks = new Mocks(this);

si vous _@RunWith(JUnit4.class).

0
lcn