【问题标题】:Change the @Component being injected in tests更改在测试中注入的@Component
【发布时间】:2014-10-23 05:53:12
【问题描述】:

我有两节课

@Component
public class A {

  @Autowired
  B b;
}

@Component
public class B {
}

它们是 Spring 通过扫描找到的。

现在我想测试A,但我需要提供不同的实现。 B,比如BMock

如何让 Spring 找到不同的 B 而不是标准(生产中只有一个)?

我的测试用以下注释:

@ContextConfiguration(locations = "classpath:/test-context.xml")

在哪个文件中定义了一些实例(DAO,..),然后在我写的测试类中

@Autowired
A testInstance;

【问题讨论】:

  • 这是一个很好的例子,说明为什么构造函数注入通常比字段注入更好。如果你重写你的类以在它的构造函数中使用B,你不需要任何复杂的东西来运行你的测试。
  • @chrylis 实际上我最喜欢你的解决方案,我觉得很简单。

标签: java spring testing dependency-injection


【解决方案1】:

你不需要 Spring。这就是依赖注入的全部意义:你可以在单元测试中明确地注入任何你想要的东西。单元测试不应该使用 Spring。

// constructor injection
B mockB = mock(B.class);
A aUnderTest = new A(mockB);

// setter injection
B mockB = mock(B.class);
A aUnderTest = new A();
aUnderTest.setB(mockB);

// Field injection, requiring reflection, done by Mockito
@Mock
private B mockB;

@InjectMocks
private A aUnderTest;

@Before
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

【讨论】:

  • 不使用mockito,我不想mock但提供一个测试实现
  • 原理是一样的。你创建你的假实现,并用这个假实现构造被测对象。如果不想使用反射,那就使用构造函数或setter注入代替字段注入。
【解决方案2】:

您可以创建单独的 xml 文件用于测试目的并注入 B 的另一个对象(BMock),在生产中您可以注入 B。所以,有两个单独的配置文件一个用于生产,另一个用于测试。

【讨论】:

  • 是的,我实际上最终删除了 @Component 并在 XML 中添加了一个元素;现在我只是有一个不同的条目(bean)用于生产 XML 和不同的测试 XML。 使用注解时有什么类似的解决方案?
  • 您不需要删除注释。您可以同时使用两者。当 xml 文件存在时,注释只会被覆盖
  • XML 有优先权?如果它们是实现相同接口的 2 个不同的类怎么办
  • 不优先。 XML 注入在注解注入之后执行。因此,如果有任何带注释的依赖项,它将覆盖。对于第二个问题,您可以使用@Qualifier
  • @Qualifier 按名称注入 bean
【解决方案3】:

根据Spring documentation

Annotation injection is performed before XML injection, thus the latter 
configuration will override the former for properties wired through both approaches.

因此,您可以在测试环境中覆盖Spring context 文件以提供测试实施。但是,如果您有多个实现,则不能单独使用 @Autowire。您还需要使用@Qualifier。所以最好的方法是 mock 测试实现并使用 setter 注入它作为 JB Nizet 回答

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多