Request Processing failed with null pointer exception because Cannot invoke Service class as it is null

144 views Asked by At

Request Processing failed with null pointer exception because Cannot invoke Service class as it is null.

I am trying to write the test cases for my controller class.

This is my User Controller class

@RestController
@RequestMapping(URLConstants.User)
@Log4j2
@RequiredArgsConstructor(onConstructor = @__({ @Autowired }))
public class UsersController {
  private final UserMapper mapper;
  private final UserService userService;
  

  @PutMapping("/{id}")
  public UserDTO update(@PathVariable("id") Long id, @RequestBody UserUpdateRequest userRequest) {
    log.debug("PUT /users/" + id + " with data" + userRequest);
    User user = CurrentUserContext.getCurrentUser();
    mapper.mergeToUser(userRequest, user);
    user = userService.update(user);
    return mapper.mapDTO(user);
  }

  
}

For this This is my Test Class

@SpringBootTest(classes = UsersController.class)
@AutoConfigureMockMvc(addFilters = false)
@ExtendWith(MockitoExtension.class)
public class UsersControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserMapper userMapper;

  @MockBean
    private UserService userService;

    @Mock
    private CurrentUserContext currentUserContext;

    @InjectMocks
    private UsersController usersController;

    private final ObjectMapper objectMapper = new ObjectMapper();




    @Test
    @DisplayName("Test successful user update")
    public void testUpdateUserSuccess() throws Exception {
        // Prepare test data
        Long userId = 1L;
        UserUpdateRequest userUpdateRequest = new UserUpdateRequest();
        userUpdateRequest.setFirstName("John");
        userUpdateRequest.setLastName("Doe");

        User updatedUser = new User();
        updatedUser.setId(userId);
        updatedUser.setFirstName(userUpdateRequest.getFirstName());
        updatedUser.setLastName(userUpdateRequest.getLastName());
        updatedUser.setStatus(UserStatus.Active);
        updatedUser.setCreatedDate(new Timestamp(System.currentTimeMillis()));
        updatedUser.setUpdatedDate(new Timestamp(System.currentTimeMillis()));

        // Mock the service method
        when(userService.update(updatedUser)).thenReturn(updatedUser);

        // Perform the request and verify the response
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(usersController).build();
        mockMvc.perform(MockMvcRequestBuilders.put("/users/{id}", userId)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(userUpdateRequest)))
                .andExpect(status().isOk());
                /*.andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(jsonPath("$.id").value(userId))
                .andExpect(jsonPath("$.firstName").value(userUpdateRequest.getFirstName()))
                .andExpect(jsonPath("$.lastName").value(userUpdateRequest.getLastName()));*/
    }

    @Test
    @DisplayName("Test invalid user update request")
    public void testUpdateUserInvalidRequest() throws Exception {
        // Prepare test data
        Long userId = 1L;
        UserUpdateRequest userUpdateRequest = new UserUpdateRequest();
        // Empty update request

        // Perform the request and verify the response
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(usersController).build();
        mockMvc.perform(MockMvcRequestBuilders.put("/users/{id}", userId)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(userUpdateRequest)))
                .andExpect(status().isBadRequest());
    }


}

Now even though I am @MockBean. private UserService userService; I am getting `this.userService is null.

Jakarta.servlet.ServletException: Request processing failed: java.lang.NullPointerException: Cannot invoke "com.app.users.services.UserService.update(com.app.users.models.User)" because "this.userService" is null
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1019)
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:925)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:550)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)


…….
…….



Cannot invoke "com.app.users.services.UserService.update(com.app.users.models.User)" because "this.userService" is null
java.lang.NullPointerException: Cannot invoke "com.app.users.services.UserService.update(com.app.users.models.User)" because "this.userService" is null
    at com.app.users.controllers.UsersController.update(UsersController.java:51)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:925)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:550)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)

What could be the possible reason for this.

2

There are 2 answers

0
OwnPetz On

Here's a breakdown of the error and how to fix it:

Understanding the Error:

Null Pointer Exception: This is a common error in programming that occurs when you try to use a variable that hasn't been assigned a value (it's "null"). In this case, the variable holding the service class is null, so you can't call its methods. Service Class: This is a class that provides specific functionality to your program. It probably does some important task related to processing requests. Troubleshooting Steps:

Identify Where the Service Class Should Be Created: Look for the part of your code where this service class is supposed to be initialized. It might be in a configuration file, a dependency injection framework, or within your code itself.

Ensure Proper Initialization: Make sure the code that creates the service class is running correctly. If it's in a configuration file, double-check for typos or errors. If it's handled by a framework, verify that the framework is set up properly.

Check for Conditional Logic: If there's code that might prevent the service class from being created under certain conditions, review that logic. For example, maybe a configuration setting determines whether the service is enabled or disabled.

Debugging Tips: Use debugging tools provided by your programming environment to step through your code line by line and see where the null value is coming from.

0
Lesiak On

TLDR: Use @WebMvcTest

Your test is all wrong.

There are 2 UsersController instances in your test.

  • One is created via SpringBootTest which brings up entire application context - controllers, services etc. Some beans are overriden via @MockBean. This controller uses your mock service.
  • The second one is created by Mockito and @InjectMocks. @MockBean are not injected into this service.

There are also 2 MockMvc instances:

  • One created via @AutoConfigureMockMvc and injected via @Autowired
  • Second created manually in your test method

In your test method you are using manually created MockMvc which makes requests to UsersController created by Mockito, which is not properly initialized - and you get NPE.

Solution

Use only one controller and one mockMvc.

However you can improve the test even further. You don't need entire spring context as:

  • you are trying to test web layer of your app
  • you are testing only one controller
  • the services it uses are mocks

This is an ideal use case for @WebMvcTest.

  • Replace @SpringBootTest with @WebMvcTest
  • @AutoConfigureMockMvc is imported via @WebMvcTest, so remove it as well
  • Remove @ExtendWith(MockitoExtension.class)
  • Do not create your own MockMvc

See: