在Spring应用程序中使用Spock自动模拟

时间:2016-05-15 20:45:20

标签: java spring unit-testing spock

我想用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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

您可以在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直接注入到Spring上下文中