Search code examples
javajunitmockitojunit5springmockito

Trying to verify a method call from abstract class on a mocked service but I get a npe


I stuck since a couple of hours on a test method.

I tried to reproduce a similar situation. I have a service who extend a abstract service with a utility method like this:

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

my testing class :

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

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

My goal is just to verify if when I go into the method whatever, the method of the abstract service is called too. I got a null pointer exception because the repository isn't not init in the mock (normal behavior I assume), but I would like to learn/understand how test this.

How could I do to fix this?

Thanks for your help


Solution

  • You are getting a NullPointerException because you are not setting an UserRepository object to MyService.

    Note that your test does not load any spring context, so the annotation @Autowired is not taking effect.

    So in order to get your test to work either:

    • add a mock UserRepository to your service via constructor or setter
    • or load a spring context to your test and add a mock UserRepository.

    For example, you could do something like the following:

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