【问题标题】:Grails integration tests and transactionsGrails 集成测试和事务
【发布时间】:2011-05-07 16:42:53
【问题描述】:

我不明白为什么这个集成测试会失败。我可以通过删除服务方法上方的@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)

我看过这个相关的帖子,但仍然没有雪茄:(

Grails Service Transactions

【问题讨论】:

    标签: grails transactions service integration-testing spring-transactions


    【解决方案1】:

    嵌套的内部事务已提交的数据更改实际上应该在父事务中立即可见。

    我真的不知道为什么它们在GroovyTestCase 的事务上下文中不是Others don't know, as well, and are using similar approaches to mine.

    考虑以下测试用例。测试用例本身不是事务性的,而是调用事务性方法。 - 这按预期工作。

    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
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        }
    }
    

    现在考虑以下“正常”事务性测试用例。嵌套事务中的数据更改在父事务中可见。

    我只能说,事务性测试用例不适用于嵌套事务,所以使用上面的非事务性测试用例
    如果我们不了解原因,我们至少可以知道我们的选择。

    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();
        }
    }
    

    与您的主要问题无关,但与您的总体意图无关,这是一个测试用例,用于检查嵌套事务是否正确回滚:

    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
            // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        }
    }
    

    最后,一些更一般的旁注,不是boolean transactional = true(虽然它似乎有效),而是static transactional = true。您的集成测试也应该extendGroovyTestCase,而不是它的子类GrailsUnitTestCase,因为您不需要后者的模拟功能。 isActive 字段应该命名为active,这样会根据命名约定自动生成一个isActive() getter。

    【讨论】:

    • 谢谢,看来这是集成测试框架的一个错误。即,代码/逻辑是正确的并且可以在正在运行的应用程序中运行,但不能在集成测试中运行?也许我应该 JIRA 吧
    • 我不认为这是一个错误(问题过于集中/突出),而是一个设计缺陷。 - 如果您应该提交 JIRA 问题(使用 Spring,而不是 Grails 框架),请在此处留言。
    • 对最后一个示例的更正(过时?):Propagation.REQUIRES_NEW 开始一个新的、不相关且独立的事务。相比之下,在Propagation.NESTED 下发生嵌套 事务(对父级可见并具有自己的保存点)。 Spring Javadocs 很好地解释了差异:docs.spring.io/spring/docs/current/javadoc-api/org/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 2014-10-31
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 2013-01-03
    • 1970-01-01
    相关资源
    最近更新 更多