![](/img/trans.png)
[英]How the Spring Security AuthenticationManager authenticate() method is able to check if the username and password sent are correct?
[英]How to mock AuthenticationManager authenticate method using Spring Security and Mockito
我正在尝试使用 Mockito 来测试用户是否点击登录 api 时,它会以 JWT 令牌响应。 但是,我不断收到来自 Spring 安全性中的 authenticationManager.authenticate() 方法的Bad Credentials
错误。 我现在正在尝试模拟这种方法,但我不断收到各种不同的错误,并且不确定我的方法是否正确。 这是我最新的实现,现在失败,因为You cannot use argument matchers outside of verification or stubbing
因为它不喜欢我使用模拟的方式。
@WebMvcTest(value = UserCommandController.class, includeFilters = {
// to include JwtUtil in spring context
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtUtil.class)})
class UserCommandControllerTest {
Logger logger = LoggerFactory.getLogger(UserCommandControllerTest.class);
@MockBean
private UserCommandService userCommandService;
@Autowired
private MockMvc mockMvc;
@MockBean
private UserDetailsServiceImpl userDetailsServiceImpl;
@MockBean
private JwtUtil jwtUtil;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
AuthenticationManager authenticationManager;
private static UserDetails dummy;
private static String jwtToken;
@BeforeEach
public void setUp() {
dummy = new User("user@email.com", "123456", new ArrayList<>());
jwtToken = jwtUtil.generateToken(dummy);
}
@Test
void testLoginReturnsJwt() throws Exception {
AuthenticationRequest authenticationRequest = new AuthenticationRequest("user@email.com", "123456");
AuthenticationResponse authenticationResponse = new AuthenticationResponse("anyjwt");
String jsonRequest = asJsonString(authenticationRequest);
String jsonResponse = asJsonString(authenticationResponse);
RequestBuilder request = MockMvcRequestBuilders
.post("/api/adverts/user/login")
.content(jsonRequest)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON);
Authentication authentication = mock(Authentication.class);
authentication.setAuthenticated(true);
when(authentication.isAuthenticated()).thenReturn(true);
when(authenticationManager.authenticate(any())).thenReturn(authentication); // Failing here
when(jwtUtil.generateToken(dummy)).thenReturn("124");
when(userDetailsServiceImpl.loadUserByUsername(eq("user@email.com"))).thenReturn(dummy);
MvcResult mvcResult = mockMvc.perform(request)
.andExpect(status().is2xxSuccessful())
.andExpect(content().json(jsonResponse, true))
.andExpect(jsonPath("$.jwt").value(isNotNull()))
.andReturn();
}
这是我的 controller:
@PostMapping(value = "/login", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> loginUser(@Valid @RequestBody AuthenticationRequest authenticationRequest) throws Exception {
try {
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword()));
} catch (BadCredentialsException e) {
throw new Exception("incorrect username or password", e);
}
UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
String jwt = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthenticationResponse(jwt));
}
谢谢你。
PS:这是我的仓库,其中设置了 AuthenticationManager: https://github.com/francislainy/adverts-backend/blob/dev_jwt/src/main/java/com/example/adverts/MyWebSecurity.java#L30
您需要AuthenticationManager
是一个模拟,而在您的代码中它不是( @Autowired
注入一个“真实”实例)。 您可以使用MockBean注解模拟 bean:
@MockBean
AuthenticationManager authenticationManager;
现在你可以随心所欲地模拟authenticationManager
了。
您的代码的另一个问题是您在断言中滥用ArgumentMatchers.isNotNull()
匹配器导致异常:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
-> at com.example.adverts.controller.user.UserCommandControllerTest.testLoginReturnsJwt(UserCommandControllerTest.java:356)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
ArgumentMatchers提供了在方法调用存根和验证中使用的匹配器。 您应该改用org.hamcrest.CoreMatchers#notNullValue() 。
通过这些修复,您的测试全部通过绿色。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.