在 Spring Boot REST API 中对 UserController 进行单元测试时,我得到了不同的结果。
控制器:
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private UserDetailsService userService;
@PermissionUserRead
@GetMapping("/user/{userName}")
public ResponseEntity<UserDetails> getUserByUsername (@PathVariable String userName){
return ResponseEntity.ok(userService.loadUserByUsername(userName));
}
}
@PermissionUserRead 是:
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasAuthority('user.read')")
public @interface PermissionUserRead {
}
我遵循两种不同的方法 没有 MockMvc:这个测试运行良好,达到预期的 200
@ExtendWith(MockitoExtension.class)
@Tag("UnitTest")
public class UserControllerUnitTest {
@InjectMocks private UserController userController;
@Mock private UserDetailsService userDetailsService;
@Test
@WithMockUser(authorities = "user.read")
public void getUserShouldReturnUser(){
String username = "testUser";
UserDetails testUser = TestAssistent.createUser(username);
when(userDetailsService.loadUserByUsername(username)).thenReturn(testUser);
ResponseEntity<UserDetails> classUnterTest = userController.getUserByUsername(username);
assertEquals(HttpStatus.OK,classUnterTest.getStatusCode());
}
}
还有一个使用 MockMvc:这个状态为 401,而不是预期的 200
@Tag("UnitTest")
@DisplayName("UserController Unit Tests")
@ExtendWith(MockitoExtension.class)
@WebMvcTest(UserController.class)
class UserControllerTest {
@Mock
UserDetailsServiceImpl userService;
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
MockMvc mockMvc;
@AfterEach
void tearDown(){
reset(userService);
}
@Test
@WithMockUser(authorities = "user.read")
void validGetUserShouldReturnUser() throws Exception{
String username = "testUser";
UserDetails testUser = TestAssistent.createUser(username);
when(userService.loadUserByUsername(username)).thenReturn(testUser);
mockMvc.perform(get("/api/user/testUser"))
.andExpect(status().isOk());
}
}
似乎我做错了什么,因为在 MockMvc 测试中我的身份验证无法正常工作?也许有人可以帮助我解释 MockMvc 在这种情况下正在做什么以及如何做?
我尝试使用不同的 @WithMockUser 变体与角色、用户名等,但没有任何效果。
我发现的控制器测试的大多数示例都使用 MockMvc,我想这就像标准,所以想使用 MockMvc 来完成它,或者不使用 MockMvc 采用我的其他解决方案“可以”吗?我没有足够的经验来判断没有 MockMvc 的测试是否会触发单元测试的所有正确内容。
谢谢你的想法
我开始对@WebMvcTest进行进一步调查,终于找到了一种更适合我在控制器上进行测试的方法,使用“REST Assured”。
我的新测试,这当然只是我测试的开始:
@WebMvcTest(UserController.class)
public class UserControllerMockMvcTest {
@MockBean
private UserDetailsService userService;
@Autowired
private MockMvc mockMvc;
@BeforeEach
void setUp(){
RestAssuredMockMvc.mockMvc(mockMvc);
}
@Test
@WithMockUser(authorities="user.read")
void shouldReturnUser(){
String username = "test";
Collection<SimpleGrantedAuthority> authorities = Collections.singletonList(
new SimpleGrantedAuthority("user.read"));
UserDetails testUser = new User(username,"password",authorities);
Mockito.when(userService.loadUserByUsername(username)).thenReturn(testUser);
RestAssuredMockMvc
.given()
.param("username",username)
.when()
.get("/api/user/{username}",username)
.then()
.statusCode(200);
}
}
我使用的资源:
https://www.youtube.com/watch?v=1rkoFTxJhNk
https://www.youtube.com/watch?v=oLtXe1wgSC8
所以我的答案是肯定的,使用 MockMvc 来确保调用 URL,就像您的代码一样,并使用“REST Assured”,对我来说,设置非常容易。