6

この統合テストが失敗する理由がわかりません。@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 (方言=org.hibernate.dialect.MySQL5InnoDBDialect) を使用しています。

私はこの関連記事を見ましたが、まだ葉巻はありません:(

Grails サービス トランザクション

4

1 に答える 1

8

ネストされた内部トランザクションがコミットしたデータ変更は、親トランザクションで即座に表示されるはずです。

そして、なぜそれらがa のトランザクションコンテキストにないのか、私には本当にわかりません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
        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    }
}

ここで、次の「通常の」トランザクション テスト ケースを考えてみましょう。ネストされたトランザクション内からのデータ変更は、親トランザクションには表示されません。

私が言えることは、トランザクション テスト ケースはネストされたトランザクションでは機能しないため、上記の非トランザクション テスト ケースを使用することです。
原因がわからない場合でも、少なくとも選択肢はわかります。

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後者のモック機能は必要ないため、統合テストもextend GroovyTestCaseそのサブクラスではなく にする必要があります。フィールドには次のように名前を付ける必要がありますGrailsUnitTestCase。ゲッターは命名規則によって自動的に生成されます。isActiveactiveisActive()

于 2010-11-10T11:32:41.513 に答える