Spring Boot 单元测试 MockMvc 行为

问题描述 投票:0回答:1

在 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 的测试是否会触发单元测试的所有正确内容。

谢谢你的想法

spring-boot rest unit-testing spring-mvc mocking
1个回答
0
投票

我开始对@WebMvcTest进行进一步调查,终于找到了一种更适合我在控制器上进行测试的方法,使用“REST Assured”。

https://rest-assured.io

我的新测试,这当然只是我测试的开始:

@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”,对我来说,设置非常容易。

© www.soinside.com 2019 - 2024. All rights reserved.