【问题标题】:Autowire mock with Spock in Spring Application在 Spring 应用程序中使用 Spock 进行 Autowire 模拟
【发布时间】:2016-09-11 15:04:03
【问题描述】:

我想用 Spock 测试我的 Java 应用程序。我有一个类AmiPlugin.java,它通过构造函数注入有两个依赖项:

@Autowired
AmiPlugin(final EC2InstanceContextProvider contextProvider,
                         final ViolationSink violationSink) {
     super(contextProvider);
     this.violationSink = violationSink;
}

我的 groovy 测试如下所示:

@ContextConfiguration(loader = SpringApplicationContextLoader   , classes = [AmiPlugin.class])
class AmiPluginSpec extends Specification{

@Autowired
AmiPlugin amiPlugin;

def "Test if plugin supports the right Cloudtrail events"(String event, Boolean supports){
    expect:
    amiPlugin.supportsEventName().test(event) == supports

    where:
    event                   | supports
    "RunInstances"          | true
    "StartInstances"        | false
    "TerminateInstances"    | false
    "StopInstances"         | false
    "Foobar"                | false
}

但是,运行它会给我一个NoSuchBeanDefinitionException。在 jUnit 中,我会在同一个文件中使用带有 @configuration 的静态类,它返回所需的模拟,但这不起作用。 使用

    @Bean
    EC2InstanceContextProvider ec2InstanceContextProviderMock(){
        EC2InstanceContextProvider provider = Mock()
        return provider
    }

也不行。

如何在 Spock 中自动装配模拟?

编辑没问题

java.lang.IllegalStateException: Failed to load ApplicationContext

    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:228)
    at org.spockframework.spring.SpringTestContextManager.prepareTestInstance(SpringTestContextManager.java:49)
    at org.spockframework.spring.SpringInterceptor.interceptSetupMethod(SpringInterceptor.java:42)
    at org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:28)
    at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:87)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'amiPlugin': Unsatisfied dependency expressed through constructor argument with index 0 of type [org.zalando.stups.fullstop.plugin.EC2InstanceContextProvider]: No qualifying bean of type [org.zalando.stups.fullstop.plugin.EC2InstanceContextProvider] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.zalando.stups.fullstop.plugin.EC2InstanceContextProvider] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1046)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
    at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
    at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 13 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.zalando.stups.fullstop.plugin.EC2InstanceContextProvider] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
    ... 31 more

【问题讨论】:

  • 请添加完整的堆栈跟踪

标签: java spring unit-testing spock


【解决方案1】:

您正在寻找的是分离的模拟,可让您创建不符合规范的模拟。 https://github.com/spockframework/spock/issues/86 - 能够将 Spock 模拟作为 Spring bean 注入。在那里你可以找到一个 hack 如何做到这一点。

2017-03-25 更新:Spock 在 1.1 版中添加了对分离模拟的完全支持。用法示例可以在in the documentationthis SO answer 中找到。

【讨论】:

    【解决方案2】:

    您可以在 Spock 1.2 中使用 SpringBean 注解:https://objectpartners.com/2018/06/14/spock-1-2-annotations-for-spring-integration-testing/

    所以你的代码会变成:

    @ContextConfiguration(loader = SpringApplicationContextLoader   , classes = [AmiPlugin.class])
    class AmiPluginSpec extends Specification{
    
    @SpringBean
    AmiPlugin amiPlugin = Mock() 
    
    def "Test if plugin supports the right Cloudtrail events"(String event, Boolean supports){
        expect:
        amiPlugin.supportsEventName().test(event) == supports
    
        where:
        event                   | supports
        "RunInstances"          | true
        "StartInstances"        | false
        "TerminateInstances"    | false
        "StopInstances"         | false
        "Foobar"                | false
    }
    

    您不再需要额外的配置类,因为 Spock 直接将 mock 注入到 spring 上下文中

    【讨论】:

    • 这是在 spring 上下文中添加 mock 的方式,所以我不明白为什么它不是正确答案
    • 澄清@VincentCouturier:如果您发布链接,这是一个正确的答案。这是一个很好的答案吗?而不是。如果链接的内容发生变化或网站出现故障,则答案无效,因为没有更多内容。因此,最好在您的答案中包含内容,并将链接作为参考/来源,就像您现在所做的那样。我收回了我的旗帜并删除了我的评论:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-22
    相关资源
    最近更新 更多