Grails 集成测试和事务
我不明白为什么这个集成测试失败。我可以通过删除服务方法上方的 @Transactional(propagation = Propagation.REQUIRES_NEW) 注释,或者在集成测试中设置 transactional = false
来让测试通过
我意识到集成测试本身是在事务中运行的,这就是我在服务方法上添加注释的原因。
class DbTests extends GrailsUnitTestCase {
boolean transactional = true
def customerService
void testTransactionsCommit() {
def orderIds = [1, 2, 3]
orderIds.each { // lets make sure they all start out as Active
def order = Order.get(it)
order.isActive = true
order.save(flush:true, validate:true, failOnError: true)
}
customerService.cancelOrders(orderIds)
orderIds.each {
def order = Order.get(it).refresh()
assertEquals false, order.isActive
}
}
我的服务方法已定义:
class CustomerService {
boolean transactional = true
@Transactional(propagation = Propagation.REQUIRES_NEW)
def cancelOrders(def orderIds) {
orderIds.each {
Order order = Order.get(it)
if(order.id == 5) //
throw new RuntimeException('Simulating an exception here, panic!')
order.isActive = false
order.save(flush:true, validate:true, failOnError: true)
println "Order.id = $order.id is ${order.isActive? 'ACTIVE' : 'CANCELLED'}"
}
}}
Order 实体是一个简单的域对象,我使用的是 Grails 1.2.1、MySQL 5.x (dialect=org.hibernate.dialect.MySQL5InnoDBDialect)
我已经看过此相关帖子,但仍然没有雪茄 :(
I don't get why this integration test fails. I can get the test to pass by either removing the @Transactional(propagation = Propagation.REQUIRES_NEW)
annotation above the service method, OR by setting transactional = false
in the Integration Test
I realize that the integration test itself is running in a transaction, and that's why I've got the annotation on the service method.
class DbTests extends GrailsUnitTestCase {
boolean transactional = true
def customerService
void testTransactionsCommit() {
def orderIds = [1, 2, 3]
orderIds.each { // lets make sure they all start out as Active
def order = Order.get(it)
order.isActive = true
order.save(flush:true, validate:true, failOnError: true)
}
customerService.cancelOrders(orderIds)
orderIds.each {
def order = Order.get(it).refresh()
assertEquals false, order.isActive
}
}
and my service method is defined:
class CustomerService {
boolean transactional = true
@Transactional(propagation = Propagation.REQUIRES_NEW)
def cancelOrders(def orderIds) {
orderIds.each {
Order order = Order.get(it)
if(order.id == 5) //
throw new RuntimeException('Simulating an exception here, panic!')
order.isActive = false
order.save(flush:true, validate:true, failOnError: true)
println "Order.id = $order.id is ${order.isActive? 'ACTIVE' : 'CANCELLED'}"
}
}}
The Order entity is a simple domain object and I'm on Grails 1.2.1, MySQL 5.x (dialect=org.hibernate.dialect.MySQL5InnoDBDialect)
I've seen this related post, but still no cigar :(
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
嵌套内部事务提交的数据更改确实应该在父事务中立即可见。
而且我真的不知道为什么它们不在
GroovyTestCase
的事务上下文。 其他人也不知道,并且正在使用与我类似的方法< /a>.考虑以下测试用例。测试用例本身不是事务性的,但调用事务性方法。 - 这按预期工作。
现在考虑以下“正常”事务测试用例。嵌套事务内的数据更改在父事务中不可见。
我只能说,事务测试用例不适用于嵌套事务,因此使用上面的非事务测试用例。
如果我们不明白原因,我们至少可以知道我们的选择。
与您的主要问题无关,但与您的总体意图相关,这是一个测试用例,用于检查嵌套事务是否回滚,正确:
最后,一些更一般的旁注,它不是
boolean transactional = true
(尽管它似乎有效),而是static transactional = true
。您的集成测试还应该扩展
GroovyTestCase
,而不是它的子类GrailsUnitTestCase
,因为您不需要后者的模拟能力。isActive
字段应命名为active
,这样,将按照命名约定自动生成isActive()
getter。Data changes that a nested, inner, transaction had committed, should be, indeed, instantly visible in the parent transaction.
And I really don't know why they are not in the transactional context of a
GroovyTestCase
. Others don't know, as well, and are using similar approaches to mine.Consider the following test case. The test case, itself, is not transactional, but calls a transactional method. - This works as expected.
Now consider the following, "normal", transactional, test case. Data changes from within the nested transaction are not visible in the parent transaction.
All I can say is, transactional test cases don't work with nested transactions, so use the non-transactional test case above.
If we don't understand the cause, we can, at least, know our options.
Not related to your primary question, but to your overall intent, here is a test case that checks whether the nested transaction is rolled back, properly:
Finally, some more general sidenotes, it's not
boolean transactional = true
(which appears to work, though), butstatic transactional = true
. Your integration tests should alsoextend
GroovyTestCase
, not its subclassGrailsUnitTestCase
, as you don't need the latter's mocking capabilities. TheisActive
field should be namedactive
as then, anisActive()
getter will be automatically generated by naming convention.