0

我有一个带有多个单元测试的 Grails 3.3.5 应用程序。当我单独运行此测试时,它们按预期运行,但是当我运行一般测试应用程序时,测试失败并显示以下消息:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.grails.beans.ConstraintsEvaluator': Cannot resolve reference to bean 'grailsDomainClassMappingContext' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grailsDatastore': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.grails.datastore.mapping.simple.SimpleMapDatastore]: Constructor threw exception; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<?, ?>]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:648)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:145)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1197)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    at org.grails.testing.GrailsUnitTest$Trait$Helper.defineBeans(GrailsUnitTest.groovy:100)
    at org.grails.testing.gorm.spock.DataTestSetupSpecInterceptor.setupDataTestBeans(DataTestSetupSpecInterceptor.groovy:50)
    at org.grails.testing.gorm.spock.DataTestSetupSpecInterceptor.configureDataTest(DataTestSetupSpecInterceptor.groovy:85)
    at org.grails.testing.gorm.spock.DataTestSetupSpecInterceptor.intercept(DataTestSetupSpecInterceptor.groovy:43)
    at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:87)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:147)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:129)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:46)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grailsDatastore': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.grails.datastore.mapping.simple.SimpleMapDatastore]: Constructor threw exception; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<?, ?>]
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:279)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1197)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:372)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1177)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1071)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
    ... 36 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.grails.datastore.mapping.simple.SimpleMapDatastore]: Constructor threw exception; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<?, ?>]
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:154)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:122)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:271)
    ... 54 more
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<?, ?>]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:324)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:206)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:187)
    at org.springframework.core.env.AbstractPropertyResolver.convertValueIfNecessary(AbstractPropertyResolver.java:266)
    at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:87)
    at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:66)
    at org.springframework.core.env.AbstractPropertyResolver.getProperty(AbstractPropertyResolver.java:169)
    at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:542)
    at org.grails.datastore.mapping.core.connections.AbstractConnectionSources.getConnectionSourceNames(AbstractConnectionSources.groovy:52)
    at org.grails.datastore.mapping.core.connections.InMemoryConnectionSources.<init>(InMemoryConnectionSources.groovy:24)
    at org.grails.datastore.mapping.core.connections.ConnectionSourcesInitializer.create(ConnectionSourcesInitializer.groovy:28)
    at org.grails.datastore.mapping.simple.SimpleMapDatastore.<init>(SimpleMapDatastore.java:117)
    at org.grails.datastore.mapping.simple.SimpleMapDatastore.<init>(SimpleMapDatastore.java:178)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)
    ... 56 more

这是单独运行时按预期工作但在全局测试中失败的单元测试之一:

package my.package

import grails.testing.gorm.DomainUnitTest
import spock.lang.Specification

class CapituloSpec extends Specification implements DomainUnitTest<Capitulo> {

    void "test id cannot be null"() {
        when:
        domain.id = null

        then:
        !domain.validate(['id'])
        domain.errors['id'].code == 'nullable'
    }

    void "test titulo cannot be null or blank"() {
        when:
        domain.titulo = null

        then:
        !domain.validate(['titulo'])
        domain.errors['titulo'].code == 'nullable'

        when:
        domain.titulo = ''

        then:
        !domain.validate(['titulo'])
        domain.errors['titulo'].code == 'blank'
    }

    void "test titulo maxSize"() {
        when: "titulo is 101 characters length"
        domain.titulo = 'a' * 101

        then: "titulo validation fails"
        !domain.validate(['titulo'])
        domain.errors['titulo'].code == 'maxSize.exceeded'

        when: "titulo is 100 characters length"
        domain.titulo = 'a' * 100

        then: "titulo validation succeed"
        domain.validate(['titulo'])
    }

    void "test capitulo ok"() {
        when:
        domain.id = 1
        domain.titulo = "Test"

        then:
        domain.validate()
    }
}

我怎样才能解决这个问题并一起而不是单独运行我的测试。

编辑:我忘了提到我正在使用两个数据源,一个默认保存几乎所有应用程序数据,另一个只保存与另一个应用程序共享的 6 个域。

4

1 回答 1

0

最后,我找到了一种避免错误并一起运行所有测试的方法。我必须使用doWithSpring闭包在所有测试中配置数据源。

首先,我使用 applicationContext 和数据源名称创建了一个 Trait 来配置数据源(如果没有给出,则使用“默认”数据源):

package my.package

import groovy.transform.CompileStatic
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.core.convert.support.ConfigurableConversionService
import org.springframework.core.convert.converter.Converter

@CompileStatic
trait MultiDatasourceTest {

    def configDatasource(ConfigurableApplicationContext applicationContext, String datasource = "default") {
        System.setProperty("grails.gorm.connections", datasource)

        ConfigurableConversionService conversionService = applicationContext.getEnvironment().getConversionService()
        conversionService.addConverter(new StringToMapConverter())
    }
}

class StringToMapConverter implements Converter<String, Map> {
    @Override
    Map convert(String source) {
        source.split(",").collectEntries({
            [(it):it]
        })
    }
}

接下来,我必须将特征添加到我的所有测试中,并configDatasource使用应用程序上下文和数据源名称(如果它不是默认名称)调用。

默认数据源

package my.package

import grails.testing.gorm.DomainUnitTest
import org.springframework.context.ConfigurableApplicationContext
import spock.lang.Specification

class CapituloSpec extends Specification implements DomainUnitTest<Capitulo>, MultiDatasourceTest {

    @Override
    Closure doWithSpring() {
        return {
            configDatasource(application.mainContext as ConfigurableApplicationContext)
        }
    }

    void "test id cannot be null"() {
        when:
        domain.id = null

        then:
        !domain.validate(['id'])
        domain.errors['id'].code == 'nullable'
    }

    // More tests
}

另一个数据源:

package my.package

import grails.testing.gorm.DomainUnitTest
import org.springframework.context.ConfigurableApplicationContext
import spock.lang.Specification

class DocumentoTeoSpec extends Specification implements DomainUnitTest<DocumentoTeo>, MultiDatasourceTest {

    @Override
    Closure doWithSpring() {
        return {
            configDatasource(application.mainContext as ConfigurableApplicationContext, "sede")
        }
    }

    void "test numeroExpediente cannot be null or blank"() {
        when:
        domain.numeroExpediente = null

        then:
        !domain.validate(['numeroExpediente'])
        domain.errors['numeroExpediente'].code == 'nullable'

        when:
        domain.numeroExpediente = ''

        then:
        !domain.validate(['numeroExpediente'])
        domain.errors['numeroExpediente'].code == 'blank'

        when: "numeroExpediente is 21 characters long"
        domain.numeroExpediente = 'a' * 21

        then: "numeroExpediente validation fails"
        !domain.validate(['numeroExpediente'])
        domain.errors['numeroExpediente'].code == 'maxSize.exceeded'

        when: "numeroExpediente is 20 characters long"
        domain.numeroExpediente = 'a' * 20

        then: "numeroExpediente validation succeed"
        domain.validate(['numeroExpediente'])
    }

    // More tests
}
于 2018-10-23T09:23:37.153 回答