使用 MockMvc 集成测试用户更新控制器
Integration testing user update controller with MockMvc
我正在尝试通过使用 MockMvc 创建一些简单的集成测试来测试用户更新控制器背后的逻辑是否正常运行。
我正在更新用户凭据,出于安全原因,密码不会在响应 dto 中返回,这样我可以限制从客户端和服务器交换密码的数量。
问题是,在测试回滚之前,如何测试密码是否真的更新了?
我尝试在测试完成前手动执行登录,如果使用原始凭据登录失败,则更新密码。
测试的简单部分很简单:
@Test
void WhenUserIsAdmin_UserCanUpdateAllFields() throws Exception {
updatedUser.setPassword("newPassword");
String jsonString = mapper.writeValueAsString(updatedUser);
MockHttpServletRequestBuilder builder = TestRequestFactory.authorizationFactoryPUT(URI, "admin");
mockMvc.perform(builder.contentType(MediaType.APPLICATION_JSON).content(jsonString))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("admin2"))
.andExpect(MockMvcResultMatchers.jsonPath("$.surnamePaternal").value("admin2"))
.andExpect(MockMvcResultMatchers.jsonPath("$.surnameMaternal").value("admin2"))
.andExpect(MockMvcResultMatchers.jsonPath("$.roleName").value("User"))
.andExpect(MockMvcResultMatchers.jsonPath("$.roleType").value("ROLE_USER"))
.andExpect(MockMvcResultMatchers.jsonPath("$.created").isNotEmpty());
}
工厂看起来像这样
public static MockHttpServletRequestBuilder authorizationFactoryPUT(String url, String user)
throws JsonProcessingException {
return MockMvcRequestBuilders.put(url)
.header(HttpHeaders.AUTHORIZATION, doLogin(user, user));
}
static String doLogin(String user, String pass) throws JsonProcessingException {
LoginRequest loginRequest = new LoginRequest(user, pass);
String resultAsJsonString = restTemplate.postForEntity(loginServer + "/login", loginRequest, String.class).getBody();
LoginResponse loginResponse = mapper.readValue(Objects.requireNonNull(resultAsJsonString), LoginResponse.class);
return loginResponse.getTokenType() + " " + loginResponse.getAccessToken();
}
在我试过的同一个测试中
LoginRequest loginRequest = new LoginRequest(user, pass);
String resultAsJsonString = restTemplate.postForEntity(loginServer + "/login", loginRequest, String.class).getBody();
LoginResponse loginResponse = mapper.readValue(Objects.requireNonNull(resultAsJsonString), LoginResponse.class);
如果在映射时响应失败或 http 响应代码为 401。那么一切正常,但数据似乎从未持久保存到数据库中。
我猜你的测试用例上面有 @Transactional,这意味着这个事务永远不会被提交,因为这是 @Test
。
因此,当您通过 restTemplate
进行 http
调用时,事务未提交并且更改对于 /logIn
端点不可见。 (这是正常的 http 请求,不受 @Test
@Transactional
的限制)
您可以使用 mockmvc
而不是 RestTemplate
来调用登录端点并断言结果。两者 mockmvc
都将受同一个交易的约束,并且更改将是可见的。
编辑
如果 /login 不是此服务的一部分,那么您应该使用用户存储库在某个时候从 db 获取密码。 repo.findUserByFirstName
也许并验证您需要什么。由于此调用将在同一事务中进行,因此结果也将有效。
我正在尝试通过使用 MockMvc 创建一些简单的集成测试来测试用户更新控制器背后的逻辑是否正常运行。
我正在更新用户凭据,出于安全原因,密码不会在响应 dto 中返回,这样我可以限制从客户端和服务器交换密码的数量。
问题是,在测试回滚之前,如何测试密码是否真的更新了?
我尝试在测试完成前手动执行登录,如果使用原始凭据登录失败,则更新密码。
测试的简单部分很简单:
@Test
void WhenUserIsAdmin_UserCanUpdateAllFields() throws Exception {
updatedUser.setPassword("newPassword");
String jsonString = mapper.writeValueAsString(updatedUser);
MockHttpServletRequestBuilder builder = TestRequestFactory.authorizationFactoryPUT(URI, "admin");
mockMvc.perform(builder.contentType(MediaType.APPLICATION_JSON).content(jsonString))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("admin2"))
.andExpect(MockMvcResultMatchers.jsonPath("$.surnamePaternal").value("admin2"))
.andExpect(MockMvcResultMatchers.jsonPath("$.surnameMaternal").value("admin2"))
.andExpect(MockMvcResultMatchers.jsonPath("$.roleName").value("User"))
.andExpect(MockMvcResultMatchers.jsonPath("$.roleType").value("ROLE_USER"))
.andExpect(MockMvcResultMatchers.jsonPath("$.created").isNotEmpty());
}
工厂看起来像这样
public static MockHttpServletRequestBuilder authorizationFactoryPUT(String url, String user)
throws JsonProcessingException {
return MockMvcRequestBuilders.put(url)
.header(HttpHeaders.AUTHORIZATION, doLogin(user, user));
}
static String doLogin(String user, String pass) throws JsonProcessingException {
LoginRequest loginRequest = new LoginRequest(user, pass);
String resultAsJsonString = restTemplate.postForEntity(loginServer + "/login", loginRequest, String.class).getBody();
LoginResponse loginResponse = mapper.readValue(Objects.requireNonNull(resultAsJsonString), LoginResponse.class);
return loginResponse.getTokenType() + " " + loginResponse.getAccessToken();
}
在我试过的同一个测试中
LoginRequest loginRequest = new LoginRequest(user, pass);
String resultAsJsonString = restTemplate.postForEntity(loginServer + "/login", loginRequest, String.class).getBody();
LoginResponse loginResponse = mapper.readValue(Objects.requireNonNull(resultAsJsonString), LoginResponse.class);
如果在映射时响应失败或 http 响应代码为 401。那么一切正常,但数据似乎从未持久保存到数据库中。
我猜你的测试用例上面有 @Transactional,这意味着这个事务永远不会被提交,因为这是 @Test
。
因此,当您通过 restTemplate
进行 http
调用时,事务未提交并且更改对于 /logIn
端点不可见。 (这是正常的 http 请求,不受 @Test
@Transactional
的限制)
您可以使用 mockmvc
而不是 RestTemplate
来调用登录端点并断言结果。两者 mockmvc
都将受同一个交易的约束,并且更改将是可见的。
编辑
如果 /login 不是此服务的一部分,那么您应该使用用户存储库在某个时候从 db 获取密码。 repo.findUserByFirstName
也许并验证您需要什么。由于此调用将在同一事务中进行,因此结果也将有效。