Sun*_*nny 6 service grails integration-testing transactions spring-transactions
我不明白为什么这个集成测试失败了.我可以通过删除@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
}
}
Run Code Online (Sandbox Code Playgroud)
我的服务方法是定义的:
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'}"
}
}}
Run Code Online (Sandbox Code Playgroud)
Order实体是一个简单的域对象,我在Grails 1.2.1,MySQL 5.x(dialect = org.hibernate.dialect.MySQL5InnoDBDialect)
我见过这个相关的帖子,但仍然没有雪茄:(
嵌套的内部事务已提交的数据更改应该在父事务中立即可见.
我真的不知道为什么他们不在交易的背景下GroovyTestCase.其他人也不知道,并且正在使用类似的方法.
考虑以下测试用例.测试用例本身不是事务性的,而是调用事务方法. - 这按预期工作.
class TransactionalMethodTest extends GroovyTestCase {
static transactional = false // test case is not transactional
def customerService
void testTransactionsCommit() {
// start a new transaction,
// setting order 1 inactive
setOrderInactive()
assert ! Order.get(1).isActive
}
@Transactional(propagation = Propagation.REQUIRED)
private void setOrderInactive() {
// make sure that order 1 is active
Order order = Order.get(1)
order.isActive = true
order.save(flush:true)
assert Order.get(1).isActive
// the following method acts in isolation level
// Propagation.REQUIRES_NEW, which means,
// a new, nested, transaction is started
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
customerService.cancelOrders([1])
// changes from the nested transaction are
// visible, instantly
assert ! Order.get(1).isActive
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
}
Run Code Online (Sandbox Code Playgroud)
现在考虑以下"正常",事务性,测试用例.嵌套事务中的数据更改在父事务中不可见.
我只能说,事务测试用例不适用于嵌套事务,因此请使用上面的非事务性测试用例.
如果我们不了解原因,我们至少可以了解我们的选择.
class TransactionalTestCaseTests extends GroovyTestCase {
static transactional = true // default; Propagation.REQUIRED
def customerService
void testTransactionsCommit() {
// make sure that order 1 is active
Order order = Order.get(1)
order.isActive = true
order.save(flush:true)
assert Order.get(1).isActive
// the following method acts in isolation level
// Propagation.REQUIRES_NEW, which means,
// a new, nested, transaction is started
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
customerService.cancelOrders([1])
// the changes from the inner transaction
// are not yet visible
assert Order.get(1).isActive
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
@Override
protected void tearDown() throws Exception {
// the changes from the inner transaction
// are still not visible
assert Order.get(1).isActive
super.tearDown();
}
}
Run Code Online (Sandbox Code Playgroud)
与您的主要问题无关,但与您的总体意图无关,这是一个测试用例,检查嵌套事务是否正确回滚:
class NestedTransactionRolledBackTests extends GroovyTestCase {
static transactional = false // test case is not transactional
def customerService
void testTransactionsCommit() {
// start a new transaction,
// setting order 1 active
setOrderActive()
assert Order.get(1).isActive
}
@Transactional(propagation = Propagation.REQUIRED)
private void setOrderActive() {
// make sure that order 1 is active
Order order = Order.get(1)
order.isActive = true
order.save(flush:true)
assert Order.get(1).isActive
// the following method acts in isolation level
// Propagation.REQUIRES_NEW, which means,
// a new, nested, transaction is started.
// This transaction will fail, and be rolled back.
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
shouldFail(NullPointerException) {
customerService.cancelOrders([1, -999])
}
// changes from the nested transaction are
// visible, instantly.
// The changes have been rolled back
assert Order.get(1).isActive
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
}
Run Code Online (Sandbox Code Playgroud)
最后,一些更一般的旁注,它不是boolean transactional = true(虽然似乎有效),但是static transactional = true.您的集成测试也应该extend GroovyTestCase,而不是它的子类GrailsUnitTestCase,因为您不需要后者的模拟功能.该isActive字段应命名active为then,isActive()将通过命名约定自动生成getter.