Spring事务导致Spring mvc集成测试失败
我正在使用SpringBoot1.3开发一个spring应用程序 我有一个MVC请求处理程序,如下所示:Spring事务导致Spring mvc集成测试失败,spring,spring-mvc,junit,spring-boot,spring-data,Spring,Spring Mvc,Junit,Spring Boot,Spring Data,我正在使用SpringBoot1.3开发一个spring应用程序 我有一个MVC请求处理程序,如下所示: @RequestMapping(method = PUT, path = "/{categoryId}") public String update(@Valid @ModelAttribute("category") Category category, BindingResult result, @GetAttribute("currentStore") Store store,
@RequestMapping(method = PUT, path = "/{categoryId}")
public String update(@Valid @ModelAttribute("category") Category category, BindingResult result, @GetAttribute("currentStore") Store store, Model model, RedirectAttributes ra) {
if (result.hasErrors()) {
model.addAttribute("categories", categoryService.activeCategories(store));
return EDIT_VIEW_NAME;
} else {
categoryService.update(category);
ra.addFlashAttribute("info", "Category updated successfully!");
return redirectTo(categoryUrls.indexPath());
}
}
下面是它的集成测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(EstoreApplication.class)
@WebIntegrationTest
@Transactional
public class CategoriesControllerIntegrationTests {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Test
@WithFactoryUser(roles = "admin")
public void testUpdateCategoryActionWithInvalidData() throws Exception {
//GIVEN
String categoryId = "category_001";
Store store = storeBuilder.getTestStore();
categoryBuilder.createListWithStore(5,store);
Category category = categoryBuilder.createWithId(categoryId);
//WHEN
this.mockMvc.perform(
put("/admin/categories/{categoryId}", categoryId)
.param("name", category.getName())
.param("title", category.getTitle())
.param("status", " ")
.param("store", store.getId())
.with(csrf())
)
//THEN
.andExpect(status().isOk())
.andExpect(view().name(CategoriesController.EDIT_VIEW_NAME))
.andExpect(model().attributeHasErrors("category"))
.andExpect(model().attributeHasFieldErrors("category", "status"))
;
}
}
删除了一些空格位,但请注意顶部的@Transactional注释
它在没有线路的情况下运行和通过:
model.addAttribute("categories", categoryService.activeCategories(store));
但是当添加它时,它给出了这个讨厌的异常,这是一个没有任何数据插入操作的bean验证异常(SpringMVC已经处理了验证错误,结果在BindingResult中)
当我在类级别上删除@Transactional present时,一切都会顺利运行,因此我认为这是事务中的一个问题
该行:
model.addAttribute("categories", categoryService.activeCategories(store));
model.addAttribute("categories", categoryService.activeCategories(store));
是查找器查询的包装器:
@Transactional(readOnly = true)
public List<Category> activeCategories(Store store) {
return categoryRepository.findAllByStoreAndStatus(store, Category.STATUS_ENABLED);
}
@Transactional(readOnly=true)
公共列表activeCategories(商店){
返回categoryRepository.findAllByStoreAndStatus(存储、类别、状态\已启用);
}
它只是一个select查询,永远不会导致bean验证错误
发生的情况是,我传递了一组无效数据以测试它不会传递,spring mvc捕获BindingResult中的错误,但似乎在测试方法结束时,某种事务回滚(我不确定,只是猜测)并尝试插入数据
如果我删除@Transactional注释,测试就会通过,但这对我来说并不实际,因为我的整个测试套件(950多个测试)都依赖于空数据库,而我使用@Transactional回滚对数据的任何更改的实现方式我想问题在于只读查询的刷新模式。如果您使用的是hibernate,那么可以通过方法上的org.springframework.data.jpa.repository.QueryHints-Annotation将flush模式设置为COMMIT()
我只能在这一点上猜测。。。等待你对我问题的回答。但是我认为您有一个@modeldattribute注释的方法来查找Category对象(类似于) 这就是为什么类别对象被加载,然后被请求中的数据修改,删除entityManager中包含无效数据的状态值=>Category对象,该数据在提交查询时被刷新 这个问题也可以通过调用entityManager.clear()或entityManager.detach(category)来缓解
我想你已经准备好OpenEntityManagerViewFilter了。您应该知道,您所做的每一次修改都将写入数据库,即使在从非只读存储库获取实体时控制器没有显式调用persist/update,除非存在事务回滚(通过引发异常或手动通知事务回滚) 。。。编辑
啊。这就是测试在没有@Transactional回滚的情况下工作的原因,因为调用@ModelAttribute注释的方法时没有事务=>entityManager立即关闭,因此在提交查询时不会刷新对类别的更改 您传递了无效数据,因此测试必须失败,但您不希望它失败?为什么测试类中有
@Transactional
?因为“SpringTestContext框架中集成测试的回滚语义默认为true”。对于@Transactional
,情况并非如此。当传递无效数据时,测试应该通过,因为spring框架捕捉到验证异常,将结果放入BindingResult对象中@Transactional with the rollback=true将删除测试期间插入的所有数据,从而在测试结束时清除空数据库@Transactional
没有rollback
属性。同样:所有测试都应该在默认情况下回滚的事务中运行。没有必要显式地做任何事情。我在finder方法上添加了一行:@QueryHints(@QueryHint(name=org.hibernate.jpa.QueryHints.HINT\u FLUSH\u MODE,value=“COMMIT”)),它可以工作:):)请您提供一点解释,或者一个指向参考文档的指针。我们将对此表示高度赞赏。谢谢,我不知道为什么会这样。在发出jpa查询时,实体管理器似乎包含一个包含无效数据的类别对象,这将导致EntityRangers状态刷新(以确保查询的数据是最新的)。。。我会尽力找出为什么会发生这种情况。同时,您可以发布categoryBuilder的相关代码吗?您可以发布@ModelAttribute注释控制器方法的代码吗?