如何注入同一接口的多个模拟

我想测试的 Java 类(称为 ServiceCaller)有这个:

The Java class (called ServiceCaller) I wish to test has this:

@Autowired @Qualifier(value="serviceA")
SomeService serviceA;

@Autowired @Qualifier(value="serviceB")
SomeService serviceB;

(有一个 doWork() 方法将检查条件并调用 A 或 B).

(there's a doWork() method that will check a condition and call either A or B).

如何将每个服务的模拟注入到适当的变量中?

How do I inject a mock of each service into the appropriate variable?

我的 Junit 有这个:

@InjectMocks ServiceCaller classUnderTest = new ServiceCaller();

@Mock SomeService mockServiceA;
@Mock SomeService mockServiceB;

然而,当我运行测试以检查在正确条件下调用的服务 A/B 时,我得到空指针,因为尚未注入模拟.

Yet when I run my tests to check that service A/B called under the correct condition, I get null pointers as the mock hasn't been injected.

显然是因为对同一接口 (SomeService) 的多个依赖项.有没有办法在声明模拟服务时指定限定符?还是我需要为依赖项设置设置器并设置老式方式?

Obviously its because of multiple dependencies on the same interface (SomeService). Is there a way to specify the qualifier when declaring the mock service? Or do I need to have setters for the dependencies and set the old fashioned way?

推荐答案

将你的 mocks 命名为 serviceA 和 serviceB 就足够了.来自 Mockito 文档:

It should be enough to name your mocks serviceA and serviceB. From Mockito documentation:

属性设置器注入;模拟将首先按类型解析,然后,如果有多个相同类型的属性,则通过匹配属性名称和模拟名称.

Property setter injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the property name and the mock name.

在你的例子中:

@InjectMocks ServiceCaller classUnderTest;

@Mock SomeService serviceA;
@Mock SomeService serviceB;

请注意,使用@InjectMocks 时无需手动创建类实例.

Note that it is not necessary to manually create class instance when using @InjectMocks.

尽管如此,我个人更喜欢使用构造函数注入依赖项.它使在测试中注入模拟变得更容易(只需使用模拟调用构造函数 - 无需反射工具或 @InjectMocks (这很有用,但隐藏了某些方面)).此外使用 TDD 可以清楚地看到测试类需要哪些依赖项,并且 IDE 可以生成您的构造函数存根.

Nevertheless I personally prefer injecting dependencies using constructor. It makes it easier to inject mocks in tests (just call a constructor with your mocks - without reflections tools or @InjectMocks (which is useful, but hides some aspects)). In addition using TDD it is clearly visible what dependencies are needed for the tested class and also IDE can generate your constructor stubs.

Spring Framework 完全支持构造函数注入:

Spring Framework completely supports constructor injection:

@Bean
public class ServiceCaller {
    private final SomeService serviceA;
    private final SomeService serviceB;

    @Autowired
    public ServiceCaller(@Qualifier("serviceA") SomeService serviceA,
                         @Qualifier("serviceB") SomeService serviceB) { ... }

    ...
}

可以使用以下代码测试此代码:

This code can be tested with:

@Mock SomeService serviceA;
@Mock SomeService serviceB;

//in a setup or test method
ServiceCaller classUnderTest = new ServiceCaller(serviceA, serviceB); 

相关文章