Модификацията на метаклас на Grails не е надеждна в рамките на единични тестове

В проект на grails 2 използвам програмирането на метакласове на Groovy, за да добавя някои методи към моите класове на домейн.

Всичко работи добре по време на изпълнение и мога да изпълнявам моите интеграционни тестове добре.

Но за единичните тестове имам някои проблеми.

Създадох тестов миксин, който отговаря за инициализиране на частта за програмиране на метаклас.

Този миксин не работи надеждно: методите, добавени към метакласа, не са налични, или са достъпни след първо извикване, или са достъпни само след извикване на предишна команда grails test-app unit:.
Това е доста проблем за непрекъснато изграждане.

Трябва да можете да възпроизведете този проблем (поне с grails 2.0.4) чрез
0) създаване на нови проекти за grails

1) добавете обект на домейн

create-domain-class playground.Data

2) добавете този клас към вашата директория src/groovy/playground

    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) Добавете този малък помощен клас (в 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

Сега изпълнете тази команда отново (понякога е необходима още една):
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 не е надеждна при изпълнение на модулни тестове? И как да заобиколите този проблем?


person Guillaume    schedule 05.11.2012    source източник
comment
Току-що започнах да се сблъсквам със същия проблем. Имахте ли късмет да разрешите това?   -  person Clark Wright    schedule 15.02.2013
comment
За съжаление не :( Бях принуден да използвам трудния начин: AST програмиране, за да добавя моя миксин по време на компилация (следвайки същия модел, използван за @TestFor). Просто си загубих времето и направих нещо сложно, когато трябваше да е лесно и просто.   -  person Guillaume    schedule 17.02.2013


Отговори (1)


Трябваше да използвам конфигурацията на grailsApplication в моя метод на клас на домейн. Сблъсках се със същия проблем. Опитайте да използвате Holders.config вместо grailsApplication.config. При мен се получи.

person Manoj Mungara    schedule 17.04.2013
comment
Здравей Manoj, благодаря много за актуализацията. Ще опитам този трик и ще дам отзиви. - person Guillaume; 18.04.2013
comment
Хм... Манодж, не използвам grailsApplication.config... Сигурен ли си в отговора си? - person Guillaume; 18.04.2013
comment
Това е моят отговор за grails 3: stackoverflow.com/questions/32780522/ - person GSAN; 13.06.2019