1

grails 2 プロジェクトでは、groovy のメタクラス プログラミングを使用して、いくつかのメソッドをドメイン クラスに追加しています。

実行時にすべてが正常に機能しており、統合テストを正常に実行できます。

しかし、単体テストにはいくつかの問題があります。

メタクラス プログラミング部分の初期化を担当するテスト ミックスインを作成しました。

この mixin は確実に実行されていません: メタクラスに追加されたメソッドが利用できないか、最初の呼び出し後に利用できるか、または前のgrails test-app unit:コマンドが呼び出された後にのみ利用できます。
これは、継続的なビルドにとってはかなりの問題です。

この問題は (少なくとも grails 2.0.4 では)
0) 新しい grails プロジェクトを作成することで再現できるはずです。

1) ドメイン オブジェクトを追加する

create-domain-class playground.Data

2) このクラスを src/groovy/playground dir に追加します

    package playground

import grails.test.mixin.domain.DomainClassUnitTestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.commons.GrailsDomainClass
import org.junit.Before

class EnhanceDomainTestMixin {

  boolean enhancerMethodCalled = false;
  GrailsApplication application
  MetaMethod mockDomainMethod

  //replace the mockDomain Method from DomainClassUnitTestMixin with this closure
  def enhancedMockDomain = { Class cl, List list ->
    def enhanced =cl.metaClass.getMetaMethod("isEnhanced")
    try {
      //run the mockDomain method to have the mocked domain class registered in the grails application
      mockDomainMethod.invoke(delegate, cl, list)
    }
    finally {
      //enhance the grails domain with a new method
      def domain = application.getDomainClass(cl.name) as GrailsDomainClass
      domain.metaClass.isEnhanced = { return true; }
      assert domain.newInstance().isEnhanced();
    }
  }

  @Before void runDomainEnhancer() {
    enhancerMethodCalled = true;
    //GrailsUnitTestMixin.initGrailsApplication() should have already been called. (at least this was not an issue here)
    application = GrailsUnitTestMixin.grailsApplication

    //pick the mockDomain method
    mockDomainMethod = DomainClassUnitTestMixin.metaClass.pickMethod("mockDomain", Class, List)

    //if the picked mockDomain has never been enhanced, wrap it.
    if(mockDomainMethod != enhancedMockDomain) {
      DomainClassUnitTestMixin.metaClass.mockDomain = enhancedMockDomain
    }
  }
}

3) この小さな utils クラスを追加します (test/unit/playground に)

package playground

class TestSetup {

  static Data d1

  static void setup() {
    d1 = new Data()
    assert d1.isEnhanced()
  }
}

4) これらのテストを、grails DataTests によって既に作成されている単体テストに追加します。

package playground

import grails.test.mixin.*

@TestFor(Data)
@TestMixin(EnhanceDomainTestMixin)
class DataTests {

  void testIsEnhancedLocal() {
    assert enhancerMethodCalled
    Data d = new Data()
    assert d.isEnhanced()
  }

  void testIsEnhancedLocalSecondTime() {
    assert enhancerMethodCalled
    Data d = new Data()
    assert d.isEnhanced()
  }

  void testIsEnhancedGlobalFirstTime() {
    assert enhancerMethodCalled
    TestSetup.setup()
    assert TestSetup.d1 != null
  }

  void testIsEnhancedGlobalSecondTime() {
    assert enhancerMethodCalled
    TestSetup.setup()
    assert TestSetup.d1 != null
  }

}

次のコマンドを実行します。 grails test-app unit:

次のような出力が必要です。

| Completed 4 unit tests, 4 failed in 1651ms
| Tests FAILED  - view reports in target\test-reports

次に、このコマンドをもう一度実行します (場合によっては、もう 1 つ必要になります)。
grails test-app unit: playground.DataTests

testMixin> grails test-app unit: playground.DataTests
| Completed 4 unit tests, 0 failed in 1384ms
| Tests PASSED - view reports in target\test-reports

では、単体テストの実行中に metaClass の変更が信頼できない理由の手がかりを誰かが持っていますか? そして、この問題を回避するにはどうすればよいですか?

4

1 に答える 1

2

ドメイン クラス メソッドで grailsApplication 構成を使用する必要がありました。私は同じ問題に遭遇しました。grailsApplication.config の代わりに Holders.config を使用してみてください。それは私のために働いた。

于 2013-04-17T19:14:16.437 に答える