Reputation: 1588
I want to create JUnit 5 test for Rest API which uses JWT token validation:
@Test
public void resetTokenTest_OK() throws Exception {
when(userService.findByResetPasswordToken(anyString())).thenReturn(trueOptional);
mockMvc.perform(post("/users/reset_token")
.contentType(MediaType.APPLICATION_JSON)
.content(ResetPasswordTokenDTO))
.andExpect(status().isOk())
.andExpect(jsonPath("$.resetPasswordToken").value(randomString_254))
.andExpect(jsonPath("$.login").value("login"))
.andExpect(jsonPath("$.status").value("200"))
.andExpect(jsonPath("$.error").value(""))
.andExpect(jsonPath("$.errorDescription").value(""));
}
I make a Mockup request using this payload:
{
"resetPasswordToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.VFb0qJ1LRg_4ujbZoRMXnVkUgiuKq5KxWqNdbKq_G9Vvz-S1zZa9LPxtHWKa64zDl2ofkT8F6jBt_K4riU-fPg",
"login": "login",
"status": "1",
"error": "",
"errorDescription": ""
}
I get NPE for this line:
Caused by: java.lang.NullPointerException
at org.engine.utils.GenericUtils.getLoggedInUser(GenericUtils.java:15)
at org.engine.rest.UsersController.lambda$resetToken$0(UsersController.java:159)
at java.base/java.util.Optional.map(Optional.java:258)
at org.engine.rest.UsersController.resetToken(UsersController.java:153)
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:564)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
Full Log:
I get NPE for this code:
return (Users) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
How I can mock the result from SecurityContextHolder.getContext().getAuthentication().getPrincipal()
in order not to get NPE?
Upvotes: 2
Views: 5896
Reputation: 13727
There are multiple ways to mock the security using @WithMockUser
, @WithAnonymousUser
, @WithUserDetails
, @WithSecurityContext
. You can use these annotations with @Test
method
SecurityContext
is of type UsernamePasswordAuthenticationToken
Using @WithAnonymousUser
allows running as an anonymous user. This is especially convenient when you wish to run most of your tests with a specific user, but want to run a few tests as an anonymous user. For example, the following will run withMockUser1 and withMockUser2 using @WithMockUser
and anonymous as an anonymous user.
While @WithMockUser
is a very convenient way to get started, it may not work in all instances. For example, it is common for applications to expect that the Authentication
principal be of a specific type. This is done so that the application can refer to the principal as the custom type and reduce coupling on Spring Security.
The custom principal is often times returned by a custom UserDetailsService
that returns an object that implements both UserDetails
and the custom type. For situations like this, it is useful to create the test user using the custom UserDetailsService. That is exactly what @WithUserDetails
does.
We can create our own annotation that uses the @WithSecurityContext to create any SecurityContext we want. For example, we might create an annotation named @WithMockCustomUser as @WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
Upvotes: 7