![](/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.