Пытаюсь проверить вызов метода из абстрактного класса на издевательской службе, но получаю npe

#java #junit #mockito #junit5 #springmockito

Вопрос:

Я застрял на пару часов на тестовом методе.

Я попытался воспроизвести аналогичную ситуацию. У меня есть служба, которая расширяет абстрактную службу с помощью утилитарного метода, подобного этому:

 public class MyService extends MyAbstractService {
    @Autowired
    private UserRepository userRepository;

    public void whatever(MyDTO myDTO) {
        User user = this.userRepository.findByName(myDTO.userId);
        hello(user.name);
    }
}

abstract class MyAbstractService {
    protected void hello(String userName) {
        System.out.printf("Hello %s", userName);
    }
}
 

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

 @Test
void whenIcallWhaterver() {
    MyService myService = Mockito.mock(MyService.class, InvocationOnMock::callRealMethod);

    myService.whatever(myDTO);
    verify(myService, only()).hello(anyString());
}
 

Моя цель-просто проверить, вызывается ли, когда я вхожу в метод, метод абстрактной службы тоже. Я получил исключение с нулевым указателем, потому что репозиторий не инициализирован в макете (я предполагаю нормальное поведение), но я хотел бы узнать/понять, как это проверить.

Как я мог это исправить?

Спасибо за вашу помощь

Комментарии:

1. Я думаю, вы могли бы попробовать что-то вроде when(mock.hello).thenDoNothing() или использовать a Spy вместо mock. Взгляните на это введение в шпионов baeldung.com/mockito-spy

Ответ №1:

Вы получаете исключение NullPointerException, потому что вы не устанавливаете объект UserRepository в MyService.

Обратите внимание, что ваш тест не загружает контекст spring, поэтому аннотация @Autowired не вступает в силу.

Так что для того, чтобы ваш тест работал, либо:

  • добавьте макет репозиции пользователя в свой сервис с помощью конструктора или установщика
  • или загрузите контекст spring в свой тест и добавьте макет описания пользователя.

Например, вы могли бы сделать что-то вроде следующего:

 @SpringBootTest(classes = MyTestConfig.class)
class MyTest {

  @MockBean
  private UserRepository userRepository;

  @SpyBean
  private MyService myService;

  @Test
  void whenIcallWhaterver() {

    // Mocks the response of the userRepository
    final User user = new User();
    user.setName("my-name");
    Mockito.when(this.userRepository.findByName(Mockito.anyString()))
            .thenReturn(user);

    final MyDTO myDTO = new MyDTO();
    myDTO.setUserId("myid");
    this.myService.whatever(myDTO);

    verify(this.myService).hello("my-name");
}

  @Configuration
  static class MyTestConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }
  }
}
 

Комментарии:

1. Звучит неплохо, спасибо за ответ