1

I've read a couple articles and seen a few videos and I though I had a grasp on how Mockito works, but still I'm unable to implement any test to my controller.

First of all, I have the following service class, which performs a request to an external API:

@Service
public class MovieService {

    RestTemplate restTemplate = new RestTemplate();
    
    public MovieResponse getMovieResponse() {
        ResponseEntity<MovieResponse> responseEntity = restTemplate.
                getForEntity("{base_url}", MovieResponse.class);
        return responseEntity.getBody();
    }

}

Then my controller calls this method and performs the sorting operation on the data:

@RestController
public class MovieController {
    
    @Autowired
    MovieService movieService = new MovieService();

    @GetMapping(value="/movies")
    public List<Movie> getAllMovies() {
        List<Movie> movies = movieService.getMovieResponse().getMovies();
        movies.sort(Comparator.comparing(Movie::getMovieName));
        return movies ;
    
    }
}

And so I tried to Mock the service response in order to test my method and verify that a sorting is happening.

@RunWith(MockitoJUnitRunner.class)
class MovieControllerTest{
    
    private MovieService movieService;
    
    @Autowired
    private MockMvc mockMvc;
    
    @Before
    void setup() {
        movieService = Mockito.mock(MovieService.class);
    }
    
    
    @Test
    void getAllMoviesTest() throws Exception {
        Movie movie1 = new Movie("Marley & Me", "2008");
        Movie movie2 = new Movie("Avatar", "2012");

        List<Movie> allMovies = Arrays.asList(movie2, movie1);
        List<Movie> expectedMovies = Arrays.asList(movie1, movie2);
        
        MovieResponse firstMovieResponse = new MovieResponse();
        firstMovieResponse.setMovies(allMovies);
        
        MovieResponse expectedMovieResponse = new MovieResponse();
        firstMovieResponse.setMovies(expectedMovies);
        
        Mockito.when(movieService.getMovieResponse())
                .thenReturn(firstMovieResponse);
        
        mockMvc.perform(get("/movies"))
                .andExpect(status().isOk())
                .andExpect((ResultMatcher) expectedMovieResponse);
  }
}

I've tried several approaches, but I think this is the closest I've got, but I get a NullPointerException in the line:

Mockito.when(movieService.getMovieResponse())
                    .thenReturn(firstMovieResponse);

And the stack trace prints the following:

java.lang.NullPointerException
    at com.example.movieservice.controller.MovieControllerTest.getAllMoviesTest(MovieControllerTest.java:50)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:84)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:768)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
2
  • Look at the stack trace. What line do you get the NPE on? Commented Jun 25, 2021 at 15:50
  • @SeanPatrickFloyd it points out this line as the NPE causer: Mockito.when(movieService.getMovieResponse()) .thenReturn(firstMovieResponse); Commented Jun 25, 2021 at 16:54

4 Answers 4

3

Usually unit test implies direct invocation of subject class and stubbing its dependencies. Code sample provided relies on @Autowired annotation which requires Spring context to be present in order to work.

Test case tries to invoke mockMvc which is not available, hence NullPointerException is thrown.

You have to explicitly annotate test class with @SpringBootTest so that context is created. Additionally, @AutoConfigureMockMvc has to be included so that MockMvc is available for autowiring.

Last, but not least, since we use Spring's context so much, instead of using plain Mockito, we have to wrap it with Spring's @MockBean instead, which will inject stub into controller.

@SpringBootTest
@AutoConfigureMockMvc
class MovieControllerTest {

    @MockBean
    private MovieService movieService;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void getAllMoviesTest() throws Exception {
        // TODO: when(movieService...).thenReturn(...);
        // TODO: mockMvc.perform(...);
    }
}

Please refer to the Spring's documentation for additional information.

Sign up to request clarification or add additional context in comments.

1 Comment

I guess what really was missing was that AutoConfigure line at the beggining of the test
3

This might come in handy if your goal is to control the ranking.

@RunWith(MockitoJUnitRunner.class)
class MovieControllerTest{
    
    @InjectMocks
    private MovieController movieController;

    @Mock
    private MovieService movieService;
    
    @Test
    void getAllMoviesTest() throws Exception {
        //Given
        Movie movie1 = new Movie("Marley & Me", "2008");
        Movie movie2 = new Movie("Avatar", "2012");
        final List<Movie> allMovies = Arrays.asList(movie2, movie1);
        
        MovieResponse firstMovieResponse = new MovieResponse();
        firstMovieResponse.setMovies(allMovies);
        
        Mockito.when(movieService.getMovieResponse()).thenReturn(firstMovieResponse);
        
        //When
        List<Movie> actualMovieList = movieController.getAllMovies();

        //Then
        assertThat(actualMovieList).containsExactly(movie1, movie2);
  }
}

@InjectMocks, to inject mock class into the test class.

PS. You can also use something different to test the ordering.

assertThat(actualMovieList).containsExactly(movie1, movie2);

1 Comment

Sorry for late reply but using your example I get the actual response from the API wich is an enormous list of movies, and so the assertion fails
2

You need to do the setup in getAllMoviesTest inside the setup function annotated by @Before. You also need to annotate movieService with @MockBean in the test class but as someone said before, look at the stack trace to find out where the NullPointerException is occurring.

1 Comment

I've checked and added the stack trace to the question, still I'm unable to understand why is it raising a NPE
1

I think the NPE is coming as the movieservice didn’t get mocked and the movieService object could be null, so it might be giving NPE. Try to put @MockBean above the moveservice. Try to run the test in debug mode.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.