我正在为我的Spring boot app Rest控制器编写集成测试。
当我用@Transactional
注释测试类时,它不会像预期的那样工作,当我删除注释时,它可以正常通过。
@Transactional
是否意味着绝对不会向数据库中写入任何内容?我的其他测试运行得很好!他们或多或少做着同样的工作。它们写/更新/读,但这个测试测试一个删除端点。flush
和clear
,它没有帮助。repository.delete
不应该从持久化上下文中删除该项吗?@Transacational
注释,我都希望它能正常工作。注意:服务层为@Transactional
这是在服务层中,由控制器调用。它在测试中不叫form。
public void delete(long groupId, String username) {
Group group = this.loadById(groupId);
User user = userService.loadByUsername(username);
groupRepository.delete(groupId);
}
编辑1个
测试失败的代码如下:
/*
* Deleting a group shouldn't delete the members of that group
*/
@Test
public void testDeleteGroupWithMembers() throws Exception {
Principal mockPrincipal = Mockito.mock(Principal.class);
Mockito.when(mockPrincipal.getName()).thenReturn(DUMMY_USERNAME);
User admin = userTestingUtil.createUser(DUMMY_USERNAME, DUMMY_USER_NAME, null, null);
Group group = groupTestingUtil.createGroup(DUMMY_GROUP_NAME, DUMMY_GROUP_DESCRIPTION, DUMMY_IMAGE_ID, admin);
User member = userTestingUtil.createUser("test1@test.test", "testUser1" , null, null);
group.addMember(member);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.delete(GROUP_ENDPOINT_URL + group.getId())
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.principal(mockPrincipal);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
int status = response.getStatus();
String content = response.getContentAsString();
Assert.assertEquals("wrong response status", 200, status);
Assert.assertEquals("wrong response content", "", content);
//This test fails, as the group is not yet deleted from the repo
Assert.assertEquals("there should be no group left", 0, Lists.newArrayList(groupRepository.findAll()).size());
Assert.assertEquals("wrong number of users exist", 2, Lists.newArrayList(userRepository.findAll()).size());
Assert.assertTrue("admin shouldn't get deleted when deleting a group", userRepository.findById(admin.getId()) != null);
Assert.assertTrue("group members shouldn't get deleted when deleting a group", userRepository.findById(member.getId()) != null);
}
在同一个测试类中工作的测试代码:
@Test
public void testCreateGroup() throws Exception {
Principal mockPrincipal = Mockito.mock(Principal.class);
Mockito.when(mockPrincipal.getName()).thenReturn(DUMMY_USERNAME);
User user = userTestingUtil.createUser(DUMMY_USERNAME, DUMMY_USER_NAME, null, null);
JSONObject jo = new JSONObject();
jo.put(NAME_FIELD_NAME, DUMMY_GROUP_NAME);
jo.put(DESCRIPTION_FIELD_NAME, DUMMY_GROUP_DESCRIPTION);
jo.put(IMAGE_FIELD_NAME, DUMMY_IMAGE);
String testGroupJson = jo.toString();
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post(GROUP_ENDPOINT_URL).content(testGroupJson)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.principal(mockPrincipal);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
int status = response.getStatus();
String content = response.getContentAsString();
List<Group> createdGroups = Lists.newArrayList(groupRepository.findAll());
Group createdGroup = createdGroups.get(0);
Assert.assertEquals("wrong response status", 200, status);
Assert.assertEquals("wrong response content", "", content);
Assert.assertEquals("wrong number of groups created", 1, createdGroups.size());
Assert.assertEquals("wrong group name", DUMMY_GROUP_NAME, createdGroup.getName());
Assert.assertEquals("wrong group description", DUMMY_GROUP_DESCRIPTION, createdGroup.getDescription());
Assert.assertEquals("wrong admin is assigned to the group", user.getId(), createdGroup.getAdmin().getId());
List<Group> groups = userTestingUtil.getOwnedGroups(user.getId());
Assert.assertEquals("wrong number of groups created for the admin", 1, groups.size());
Assert.assertEquals("wrong group is assigned to the admin", user.getOwnedGroups().get(0).getId(), createdGroup.getAdmin().getId());
Assert.assertTrue("image file was not created", CommonUtils.getImageFile(createdGroup.getImageId()).exists());
}
在GroupService
中创建和删除方法:
public void create(String groupName, String description, String image, String username) throws IOException {
User user = userService.loadByUsername(username);
Group group = new Group();
group.setAdmin(user);
group.setName(groupName);
group.setDescription(description);
String imageId = CommonUtils.decodeBase64AndSaveImage(image);
if (imageId != null) {
group.setImageId(imageId);
}
user.addOwnedGroup(group);
groupRepository.save(group);
logger.debug("Group with name " + group.getName() + " and id " + group.getId() + " was created");
}
public void delete(long groupId, String username) {
Group group = this.loadById(groupId);
User user = userService.loadByUsername(username);
validateAdminAccessToGroup(group, user);
groupRepository.delete(groupId);
logger.debug("Group with id " + groupId + " was deleted");
}
rest控制器的代码:
/*
* Create a group
*/
@RequestMapping(path = "", method = RequestMethod.POST)
public void create(@RequestBody PostGroupDto groupDto, Principal principal, BindingResult result) throws IOException {
createGroupDtoValidator.validate(groupDto, result);
if (result.hasErrors()) {
throw new ValidationException(result.getFieldError().getCode());
}
groupService.create(groupDto.getName(), groupDto.getDescription(), groupDto.getImage(), principal.getName());
}
/*
* Delete a group
*/
@RequestMapping(path = "/{groupId}", method = RequestMethod.DELETE)
public void delete(@PathVariable long groupId, Principal principal) {
groupService.delete(groupId, principal.getName());
}
编辑2
我尝试删除Group
而不是User
,但也不起作用。在相同的方法(组服务图层的delete
方法)中,创建一个组可以,但删除不可以!
发布于 2017-08-26 15:25:44
经过一段时间的挖掘,我发现了问题所在。User
类有一个Group
实体列表。在Group
服务层的delete
方法中,我必须从用户指向的组列表中删除已删除的组。令人失望的是,持久上下文没有为它抛出任何异常。
发布于 2017-08-23 16:41:21
当使用@Transactional
注释测试时,它会回滚。
请发布您的其他测试以了解更多详细信息。
防止用测试数据填充数据库。
在哪里检查项是否已从持久性上下文中删除?
测试中的每个方法都包装了Spring事务,因此数据可能要到测试结束时才会提交。
查看详细答案:
发布于 2017-09-01 17:51:14
从更广泛的角度来看,我认为你可能在工作中使用了错误的工具。
测试需要相互隔离,这样测试运行的顺序才不会对结果产生影响。
这是在JUnit中实现的,例如,通过为要执行的每个测试方法创建测试类的新实例。
对于测试特定事务中的逻辑的集成测试,这可以通过在测试开始时启动事务,然后在测试结束时回滚它来实现。因此,该数据库不携带任何特定于测试的数据,因此可供下一次测试使用。
为了测试rest控制器,可能需要另一种方法。当事务在您的生产环境中运行时,您可能会在该控制器中的某个位置启动事务,而不是在调用实际的rest控制器代码之前。您可能会遇到控制器导致与数据库以外的其他系统进行通信的情况(如果控制器测试中允许这样做的话)。或者,您可能会遇到在同一rest控制器调用中完成多个事务的情况,或者使用非默认事务隔离的事务,等等。这些用例不能使用@Transactional
测试用例的默认行为。
因此,您可能希望重新考虑您的测试方法,并定义每组测试的测试范围。然后,基于这些作用域,您可以定义如何在每个作用域中隔离测试的策略。然后,对于每个测试运行,应用适当的策略。
https://stackoverflow.com/questions/45831099
复制相似问题