我正在进行单元测试,该测试需要一些由弹簧注入的对象,因此我使用:
@RunWith(SpringRunner.class)
@Import({BConfig.class})
public class ATest {
private A a;
@Autowired
private B b;
@Before
public void init() {
a = new A(b);
}
}
但是,BConfig类具有一个自动连接的字段c,在此测试中我不需要:
class BConfig {
@Autowired
C c;
@Bean
public getB() {
return new B();
}
// other method code will use field c
}
自动连接的c字段将从@PostConstruct中的redis获取数据,这些数据在单元测试中不存在。如果我不忽略这一点,由于redis数据不存在,单元测试将报告错误。
我有一个解决方案,使C成为2个子类CProduction和CUnitTest,它们都实现了接口C,然后是活动概要文件,以在单元测试中使用CUnitTest。但是,这是一种侵入性操作,因为如果不进行单元测试,C的接口将毫无用处。
有更好的方法吗?
答案 0 :(得分:2)
考虑使用:
@RunWith(SpringRunner.class)
@ContextConfiguration({BConfig.class})
class ATest {
@MockBean // will place a mock implementation of C to the context instead of real one that tries to connect with Redis.
C c;
...
}
请注意,如果C是接口,它将无缝运行。否则,它将尝试通过继承(从C扩展过来的东西)创建代理,并且如果C在构造函数中具有一些与Redis相关的代码,它可能仍会尝试调用它。
更新1
基于OP的评论,试图阐明答案:
spring应用程序上下文启动时,它基本上会解析所有bean并注入所需的内容。
首先,它解析bean定义(元数据)-真实的类,范围等。 然后,它按照允许注入的顺序创建bean。例如,如果A类具有一个B类字段(都是bean),那么spring必须首先创建B,然后创建a并将B注入A。
现在,@MockBean
是与测试相关的钩子。它告诉测试中使用的spring应用程序上下文,spring可以解析@Configuration
类之外的常规bean定义或由于放置了@Component
注释而找到组件,而应使用Mock -在运行时使用Mockito之类的框架生成的东西。
此模拟实现以后可以用来指定期望值(请参阅Mockito基础教程,互联网上有很多这样的期望值),但对您而言更重要的是,它不会连接到Redis,因为此模拟实现没有任何与Redis相关的代码。
更新2
配置应重写如下:
@Configuration
public class BConfig {
@Bean
public getB() {
return new B();
}
@Bean
public C c() {
return new C();
}
// other method code will use field c:
// if for example D uses C: then you can:
@Bean
public D d(C c) {
return new D(c);
}
}