我在Spock中编写了一个Spring,其中注入的依赖项需要在bean的构造函数中执行一些操作。
我已经在我的规范中创建了一个模拟并用@SpringBean对其进行了注释,并为模拟定义了一些行为,然后我期望它被注入到依赖于模拟类的bean中。一些被模拟的实例被注入到bean中,但是我无法定义行为,这是我所期望的。
我可以从(https://spockframework.org/spock/docs/1.3/module_spring.html)看到:
Spock的@SpringBean实际上在ApplicationContext中创建了一个代理,该代理将所有内容转发给当前的模拟实例。代理的类型由带注释的字段的类型决定。代理在安装阶段将自己附加到当前的模拟,这就是为什么必须在初始化字段时创建模拟。
这个实例似乎不一样,我猜文档中的引号是这样说的,但我希望能够定义行为,并在bean中有它,但是方法只返回默认值,这意味着模拟注入没有重新定义它的行为。
从我实现的另一个扩展测试中可以看出,它的工作方式与我预期的一样,即可以在规范中定义行为并按预期注入,但为了示例的目的,我隔离了问题。
解决办法是显式创建类并注入依赖项,但在发生此问题的测试中,依赖项必须注入依赖关系层次结构中非常深的依赖项中。
有人能确定我错过了什么吗?
试验结果如下:
package com.test.springmockspock
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification
@SpringBootTest
class SpringspockmockApplicationSpec extends Specification {
@Autowired
SpringspockmockApplication sut
@SpringBean
Factory factory = Mock() {
getInt() >> 99
}
@Autowired
Factory autowiredFactory
void 'hello'() {
when:
def insideSUTFactory = sut.factory
then:
factory.getInt() == 99
// sut.intFromFactory == 42 // this should have been 99
autowiredFactory == insideSUTFactory // true
factory == insideSUTFactory // false (but should have been true)
}
}
工厂的课程是:
package com.test.springmockspock;
import org.springframework.stereotype.Component;
@Component
public class Factory {
public Producer get() {
return new Producer();
}
public int getInt() {
return 45;
}
}
package com.test.springmockspock;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("com.test.springmockspock")
@SpringBootApplication
public class SpringspockmockApplication implements CommandLineRunner {
private final Factory factory;
private final Producer producer;
public SpringspockmockApplication(Factory factory) {
this.factory = factory;
this.producer = factory.get();
return;
}
public static void main(String[] args) {
SpringApplication.run(SpringspockmockApplication.class, args);
}
public Factory getFactory() {
return factory;
}
@Override
public void run(String... args) throws Exception {
System.out.println("Hello world");
}
public int getIntFromFactory() {
return factory.getInt();
}
}
The build.gradle.kts
plugins {
groovy
application
id("org.springframework.boot") version "2.5.0"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
}
repositories {
mavenCentral()
}
dependencies {
// Use the latest Groovy version for Spock testing
testImplementation("org.codehaus.groovy:groovy:3.0.7")
// Use the awesome Spock testing and specification framework even with Java
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.spockframework:spock-spring:2.0-M4-groovy-3.0")
testImplementation("org.spockframework:spock-core:2.0-M4-groovy-3.0")
testImplementation("junit:junit:4.13.1")
testRuntimeOnly("net.bytebuddy:byte-buddy:1.11.0") // allows mocking of classes (in addition to interfaces)
testRuntimeOnly("org.objenesis:objenesis:3.2") // allows mocking of classes without default constructor (together with ByteBuddy or CGLIB)
// This dependency is used by the application.
implementation("com.google.guava:guava:30.0-jre")
implementation("org.springframework.boot:spring-boot-starter")
}
application {
mainClass.set("com.test.springmockspock.App")
}
发布于 2021-05-28 17:20:33
你已经引用了确切的问题。@SpringBean
将创建一个代理,该代理稍后会附加到规范中,就像在Spock世界中一样,交互是由规范管理的,而不是单个的模拟。
现在,spring上下文将在将模拟附加到规范之前初始化,因此您只获得代理实例而不进行任何交互。然后将这个代理注入构造函数,在构造函数中它将响应它的默认行为(返回null或0)。初始化上下文之后,模拟将被附加到规范中,现在可以处理交互。
https://stackoverflow.com/questions/67716891
复制相似问题