Получение исключения NullPointerException при вызове вложенного метода класса Service с использованием mockito

Я пишу тестовые примеры JUnit для своих классов обслуживания. Я создал фиктивные данные, чтобы понять свой сценарий.

@Service
MainClass {
    @Autowired
    C c;
    public void someServiceMethod(){
        ResultClass someResult = c.getResult(string,string, int, int, List<String>,boolean);
    }
}

@Service
public class C {
    @Autowired
    SomeRepository someRepository;
    public ResultClass getResult(string,string, int, int, List<String>,boolean){
        ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);
    }
}

@Test
MainClassTest {
    @MockBean
    SomeRepository someRepository;
    when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);

    //calling MainClass method
    MainClass.someServiceMethod();
}

Метод getSomeData () класса C возвращает объект класса ABC, который имеет значение NULL, а затем устанавливается в другой объект того же типа. После установки значения я получаю NULLPointerException, поскольку ABC равно NULL. Кто-нибудь знает, где я ошибаюсь?

Признаюсь, я не очень хорошо знаком с этим синтаксисом для использования Mockito, но мне кажется, что ваш метод getSomeData возвращает ResultClass, но когда вы вставляете его в заглушку, вы возвращаете объект SomeRepository. Попробуйте создать ResultClass и вернуть его.

Stalemate Of Tuning 27.12.2018 17:26

Каковы ваши намерения? Вы хотите только имитировать результат getSomeData () someRepository и протестировать someServiceMethod () MainClass?

Ken Chan 27.12.2018 17:29

@KenChan О да, это хороший аргумент. Если OP намеревался протестировать someServiceMethod, тогда OP должен заглушать getResult, а не getSomeData. Думаю, нужна дополнительная информация.

Stalemate Of Tuning 27.12.2018 17:37
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
640
3

Ответы 3

Вы не возвращаете ожидаемый объект при написании фиктивного оператора

    @Service
public class C {
    @Autowired
    SomeRepository someRepository;
    public ResultClass getResult(string,string, int, int, List<String>,boolean){
        ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);

        //Your return type should be ResultClass 
        // Where your return statement
        // What is ABC?
    }
}

@Test
MainClassTest {
    @MockBean
    SomeRepository someRepository;
    when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);
    // Why are you returning SomeRepository, This Should return object of ABC

@MockBean 
ABC mockResultClass
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(mockResultClass);

    //calling MainClass method
    MainClass.someServiceMethod();
}

Вы вызываете MainClass.someServiceMethod(), который, в свою очередь, вызывает getResult класса C. Вы должны издеваться над классом C и использовать when-thenReturn для getResult() класса C, если вы намерены протестировать someServiceMethod() класса Main. Autowired здесь не будет работать, поскольку это модульный тест, и, следовательно, экземпляр C c в классе Main будет нулевым. Что-то вроде ниже:

@MockBean
C c;
when(c.getResult(anyString(), anyString(),anyInt(),anyInt(), any(List.class), anyBoolean()).thenReturn(someResult);

c.getResult(string,string, int, int, List<String>,boolean);

Итак, прежде всего, нам нужно четко понимать, что именно вы тестируете. Если вы пытаетесь выполнить модульное тестирование someServiceMethod внутри MainClass, это означает, что вам НЕ следует также тестировать функциональность someRepository. Идея состоит в том, что каждый модульный тест должен тестировать только эту единицу кода. Итак, для этого нам нужно использовать заглушки в качестве замены для того, что на самом деле произойдет, когда вы вызовете методы, принадлежащие другим классам. Затем мы бы написали другой модульный тест только для someRepository.getSomeData(), чтобы убедиться, что он также работает должным образом. Таким образом, когда позже мы получим ошибку, мы будем точно знать, где мы столкнулись с проблемой.

Другая проблема, которую я вижу, заключается в очевидном несоответствии типов возвращаемых значений для getResult() в C. Метод говорит, что возвращает ResultClass, но когда вы вызываете getSomeData, вы ожидаете объект ABC. Либо вы упустили детали, в которых преобразовываете объект обратно в ResultClass, либо это ошибка. Я собираюсь предположить первое, если вы не скажете иначе.

Имея это в виду, давайте напишем наш тест. Вот как бы я написал тест:

@RunWith(SpringRunner.class)
public class MainClassTest {

    @Mock
    C c;

    @InjectMocks
    MainClass mainClass;

    @Test
    public void testSomeServiceMethod {

        ResultClass resultClass = new ResultClass(); //relevant constructor details here, mockbean, etc. you get the idea

        //set any desired data for resultClass here

        Mockito.when(c.getResult(anyString(), anyString(), 
            anyInt(), anyInt(), any(List.class), anyBoolean()))
            .thenReturn(resultClass);

        ResultClass newResult = mainClass.someServiceMethod();

        //relevant test assertions here
    }
}

Как видите, мы создаем ResultClass в тесте и говорим Mockito вернуть его при вызове getResult вместо того, что вы обычно ожидаете вернуть. Хотя сейчас функциональность может показаться ограниченной, это предпочтительнее, поскольку мы тестируем только MainClass, а не остальные вызовы наших методов.

В дополнение к этому мы можем (и должны) писать тесты для getResult в C и getSomeData в SomeRepository. Я предоставлю вам написать эти тесты.

Обновлено: случайно опубликовал немного раньше, сейчас исправляю.

Другие вопросы по теме