Модульный тест класса домена Grails, проблема с настройкой ограничения - java.lang.NoClassDefFoundError: Не удалось инициализировать
Мой модульный тест Grails для класса домена выдает это исключение:
| java.lang.NoClassDefFoundError: Could not initialize class com.pkg.common.Configuration
at com.pkg.DomainClass$__clinit__closure1.doCall(DomainClass.groovy:10)
at org.grails.datastore.mapping.config.groovy.MappingConfigurationBuilder.evaluate(MappingConfigurationBuilder.groovy:72)
at org.grails.datastore.mapping.config.AbstractGormMappingFactory.createMappedForm(AbstractGormMappingFactory.java:51)
at org.grails.datastore.mapping.keyvalue.mapping.config.GormKeyValueMappingFactory.createMappedForm(GormKeyValueMappingFactory.java:37)
at org.grails.datastore.mapping.keyvalue.mapping.config.GormKeyValueMappingFactory.createMappedForm(GormKeyValueMappingFactory.java:27)
at org.grails.datastore.mapping.keyvalue.mapping.config.KeyValuePersistentEntity.<init>(KeyValuePersistentEntity.java:33)
at org.grails.datastore.mapping.keyvalue.mapping.config.KeyValueMappingContext.createPersistentEntity(KeyValueMappingContext.java:89)
at org.grails.datastore.mapping.model.AbstractMappingContext.addPersistentEntityInternal(AbstractMappingContext.java:159)
at org.grails.datastore.mapping.model.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:152)
at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:133)
at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:129)
Ниже приведен мой урезанный класс домена:
package com.pkg
import com.pkg.common.Configuration
class DomainClass {
String subject
static constraints = {
subject(maxSize: 100, nullable: false, blank: false, matches: Configuration.ALLOWED_TEXT_CHARS)
}
}
Мой класс com.pkg.common.Configuration - это просто Singleton со статическими свойствами:
package com.pkg.common
import grails.util.Holders
class Configuration{
final public static String ALLOWED_TEXT_CHARS = "${Holders.grailsApplication.metadata["allowed.text.chars"]}"
}
"allow.text.chars" - это RegEx, определенный в application.properties:
allowed.text.chars=[a-zA-Z0-9\\p{L}\\p{Digit}_"` $ \\-'_&;\:#()/\\.,!\\?%*|<>]+
Теперь, почему это так больно, просто чтобы установить ограничение? Ну, мне нужно сохранить все текстовые поля в моих 15+ доменах, согласованные с точки зрения символов, которые они принимают. Поскольку это бизнес-требование, мне нужно сохранить его настраиваемым, чтобы мы могли в любое время удалить / добавить любые новые символы без риска трогать слишком много классов домена ради целостности. В дополнение к этому, я хочу использовать доступное регулярное выражение и в других классах Service.
Теперь эта реализация хорошо работает в интеграции run-app, production & test-app: единственная проблема - в случаях модульных тестов. Что я могу понять, так это то, что такие зависимости Grails не сможет внедрить автоматически в модульном тесте env.
Можем ли мы смоделировать и добавить класс конфигурации, используя метакласс манипуляции? Я пытался, но потерпел неудачу. (Читай: я не знаю, как работают насмешки для статических классов и как добавить их в метакласс)
Или, если есть другой способ реализовать такую концепцию?
Многие Thnx
1 ответ
Чтобы избежать повторения ограничения для нескольких классов домена, вы можете использовать либо общее ограничение, либо глобальное ограничение.
Если вы используете глобальное ограничение, то для предоставления вам доступа к регулярному выражению из класса обслуживания сохраните регулярное выражение в отдельном параметре конфигурации.
Config.groovy
allowed.text.chars='bigLongRegex'
grails.gorm.default.constraints = {
subject matches: allowed.text.chars
}
Класс обслуживания
class MyService {
GrailsApplication grailsApplication
void something() {
String regex = grailsApplication.config.allowed.text.chars
}
}
Если вы хотите написать модульный тест, который проверяет ограничение класса домена, не забудьте добавить @Mock
аннотация, например
@Mock([DomainClass])
class DomainClassTests {
void testConstraint() {
// test code goes here
}
}