在@Import类中模拟自动接线字段

时间:2019-11-25 06:49:31

标签: spring unit-testing

我正在进行单元测试,该测试需要一些由弹簧注入的对象,因此我使用:

@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的接口将毫无用处。

有更好的方法吗?

1 个答案:

答案 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);
    } 
}