В проект на 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 не е надеждна при изпълнение на модулни тестове? И как да заобиколите този проблем?