Подтвердить что ты не робот

Mockito - исключение NullpointerException при методе stubbing

Итак, я начал писать тесты для нашего Java- Spring -проекта.

Я использую JUnit и Mockito. Он сказал, что когда я использую параметр when()... thenReturn(), я могу имитировать сервисы, не моделируя их или так. Так что я хочу сделать, чтобы установить:

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

Но независимо от того, какое это условие я делаю, я всегда получаю исключение NullpointerException, что, конечно, имеет смысл, потому что ввод является нулевым.

Также, когда я пытаюсь высмеять другой метод из объекта:

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

Там я также получаю Nullpointer, потому что для метода нужна переменная, которая не задана.

Но я хочу использовать when().. thenReturn(), чтобы обойти создание этой переменной и так далее. Я просто хочу убедиться, что, если какой-либо класс вызывает этот метод, то независимо от того, просто верните true или список выше.

Является ли это в основном недоразумением с моей стороны или что-то еще не так?

Код:

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

И вот мой тестовый класс:

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


}
4b9b3361

Ответ 1

Возвращаемое по умолчанию значение методов, которые вы еще не пропустили, равно false для булевых методов, пустой коллекции или карты для методов, возвращающих коллекции или карты, и null в противном случае.

Это также относится к вызовам методов внутри when(...). В примере when(myService.getListWithData(inputData).get()) будет возникать исключение NullPointerException, потому что myService.getListWithData(inputData) есть null - он еще не был пропущен.

Один из вариантов - создать mocks для всех промежуточных возвращаемых значений и заглушить их перед использованием. Например:

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

Или, альтернативно, вы можете указать другой ответ по умолчанию при создании макета, чтобы методы возвращали новый макет вместо null: RETURNS_DEEP_STUBS

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

Вы должны прочитать Javadoc Mockito.RETURNS_DEEP_STUBS, который объясняет это более подробно, а также имеет некоторые предупреждения об использовании.

Надеюсь, это поможет. Просто обратите внимание, что ваш примерный код, похоже, имеет больше проблем, таких как отсутствие утверждений или верификационных утверждений и вызывать сеттеры на mocks (что не имеет никакого эффекта).

Ответ 2

У меня была эта проблема, и моя проблема заключалась в том, что я вызывал свой метод с any() вместо anyInt(). Итак, у меня было:

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

и мне пришлось изменить его на:

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

Я понятия не имею, почему это вызвало исключение NullPointerException. Может быть, это поможет следующей бедной душе.

Ответ 3

У меня была такая же проблема, и моя проблема была просто в том, что я не правильно аннотировал класс, используя @RunWith. В вашем примере убедитесь, что у вас есть:

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

Как только я это сделал, NullPointerExceptions исчезли.

Ответ 4

Для меня причина, по которой я получал NPE, заключается в том, что я использовал Mockito.any() насмешки примитивов. Я обнаружил, что, переключаясь на использование правильного варианта от mockito, избавляется от ошибок.

Например, чтобы смоделировать функцию, которая принимает примитив long качестве параметра, вместо использования any(), вам нужно быть более конкретным и заменить его any(Long.class) или Mockito.anyLong().

Надеюсь, что это помогает кому-то.

Ответ 5

Для будущих читателей еще одна причина использования NPE при использовании mocks - забыть инициализировать mocks следующим образом:

@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");
   // ...
}

Также убедитесь, что вы используете JUnit для всех аннотаций. Однажды я случайно создал тест с @Test из testNG, поэтому @Before не работал с ним (в testNG аннотация @BeforeTest)

Ответ 6

Угловой корпус:
Если вы используете Scala и пытаетесь создать any сопоставитель для класса значений, вы получите бесполезный NPE.

Таким образом, данный case class ValueClass(value: Int) extends AnyVal, что вы хотите сделать, это ValueClass(anyInt) вместо any[ValueClass]

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

Этот другой SO вопрос более конкретно об этом, но вы пропустите его, если не знаете, что проблема связана с классами значений.

Ответ 7

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

 }
}

Все приведенные выше комментарии не требуются { mockContext = Mockito.mock(Context.class); }, если вы используете @Mock Annotation to Context mockContext;

@Mock 
Context mockContext; 

Но это будет работать, если вы используете только @RunWith (MockitoJUnitRunner.class). Согласно Mockito вы можете создать фиктивный объект, используя @Mock или Mockito.mock(Context.class); ,

Я получил NullpointerException из-за использования @RunWith (PowerMockRunner.class), вместо этого я изменил на @RunWith (MockitoJUnitRunner.class), он работает нормально

Ответ 8

вам нужно инициализировать метод MockitoAnnotations.initMocks(this) для инициализации аннотированных полей.

   @Before public void initMocks() {
       MockitoAnnotations.initMocks(this);
   }

для получения более подробной информации см. документ

Ответ 9

столкнулся с той же проблемой, решение, которое работало для меня:

Вместо того, чтобы издеваться над интерфейсом службы, я использовал @InjectMocks для проверки реализации службы:

@InjectMocks
private exampleServiceImpl exampleServiceMock;

вместо:

@Mock
private exampleService exampleServiceMock;

Ответ 10

Ответ Эда Уэбба помог в моем случае. И вместо этого вы также можете попробовать добавить

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

если вы @RunWith(JUnit4.class).

Ответ 11

В моем случае я пропустил сначала добавить

PowerMockito.spy(ClassWhichNeedToBeStaticMocked.class);

так что это может быть полезно для тех, кто видит такую ошибку

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)

Ответ 12

Ни один из этих ответов не работал для меня. Этот ответ не решает проблему с ОП, но так как этот пост - единственный, который обнаруживает поиск по этой проблеме, я делюсь своим ответом здесь.

Я сталкивался с этой проблемой при написании юнит-тестов для Android. Проблема заключалась в том, что тестируемое действие расширило AppCompatActivity вместо Activity. Чтобы это исправить, я смогла просто заменить AppCompatActivity на Activity поскольку мне это действительно не нужно. Это не может быть жизнеспособным решением для всех, но, надеюсь, знание основной причины поможет кому-то.

Ответ 13

Ни один из приведенных выше ответов не помог мне. Я изо всех сил пытался понять, почему код работает на Java, а не на Kotlin.

Тогда я понял это из этой темы.

Вы должны сделать класс и функции-члены open, иначе NPE был брошен.

После выполнения функции open тесты начали проходить.

С тем же успехом вы можете использовать плагин "all-open":

У Kotlin есть классы и их члены окончательные по умолчанию, что делает неудобным использование фреймворков и библиотек, таких как Spring AOP, которые требуют, чтобы классы были открыты. Плагин all-open компилятора адаптирует Kotlin к требованиям этих фреймворков и делает аннотации классов с определенной аннотацией, а их члены открываются без явного ключевого слова open.