2012-03-26 139 views
4

我有一个非常简单的设置 - 一个调用服务方法的控制器。在此服务中,我将一个对象保存到数据库中,并使用注入的JMSTemplate将JMS消息发送到队列 - 一旦保存 - 。该服务默认启用交易。Grails:集成测试中的事务

当手动测试 - 在ActiveMQ服务器关闭的情况下 - 抛出异常并且事务回滚 - 实际上对象也没有保存到数据库。都好。

但是,当我通过集成测试(使用ActiveMQ仍在运行)执行此操作时,我调用assert来检查该对象是否在调用控制器后使用计数查询保存在数据库中,并没有说计数是1.我已经证实,当测试通过在测试开始时添加另一个断言来确保计数为0时,DB没有任何这些对象。

这是预期的行为(可能是由于集成测试环境中的事务性质)还是我可能做错了什么?由于JMS服务器关闭,异常仍然被抛出 - 这是一个RuntimeException。

Grails integration tests and transactions给人的印象是这是预期的 - 在这种情况下,是否有任何关于如何测试集成测试中的事务行为的最佳实践的建议?

+0

如果我没有记错,事务才会回滚,直到测试完成。因此,当您执行断言时,看起来数据已保存到数据库,因为事务没有回滚。 – GreyBeardedGeek 2012-03-26 03:50:51

+0

是的,这看起来确实如此,因为同一事务似乎被用于整个测试和控制器。想知道是否有这样的情况下使用的标准范例。我不想仅仅为了测试而更改控制器代码,以使其需要新的事务。 – Rama 2012-03-26 04:18:17

+1

此博客文章 - http://www.fepede.net/blog/?p=27显示如何使测试非事务性,这将导致控制器和服务拥有自己的事务(不使用测试的事务) 。缺点是如果不抛出异常,事务将会提交,你必须清理自己。 – GreyBeardedGeek 2012-03-27 04:53:49

回答

7

不知道为什么每个人都评论而不是回答,因为评论确实暴露了答案。我会跳进来试图阻止回答点!

是的,在Spock测试中,包括whens,thens,givens等在内的整个测试都用完了同一个事务。因此,在测试完成之前,您不会看到您希望的回滚。

您可以通过在测试类的顶部添加“static transactional = false”来将测试设置为非事务性测试。当然,后果是你需要在运行测试后清理数据库(如果数据库卫生对你很重要)。这里的一个大问题是Grails IntegrationSpec类有一个错误,当你尝试将事务设置为false时,它会炸毁。这方面有着解决这一问题:

Grails 2.3 IntegrationSpec cannot be transactional false

基本上,所有grails.test.spock.IntegrationSpec代码复制到自己的类和替换版本尊重的事务性质的几种方法考试。