Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何注入同一接口的多个模拟_Java_Spring_Dependency Injection_Mocking_Mockito - Fatal编程技术网

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

Java 如何注入同一接口的多个模拟,java,spring,dependency-injection,mocking,mockito,Java,Spring,Dependency Injection,Mocking,Mockito,我希望测试的Java类(称为ServiceCaller)具有以下特性: @Autowired @Qualifier(value="serviceA") SomeService serviceA; @Autowired @Qualifier(value="serviceB") SomeService serviceB; @InjectMocks ServiceCaller classUnderTest = new ServiceCaller(); @Mock SomeService mock

我希望测试的Java类(称为
ServiceCaller
)具有以下特性:

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

@Autowired @Qualifier(value="serviceB")
SomeService serviceB;
@InjectMocks ServiceCaller classUnderTest = new ServiceCaller();

@Mock SomeService mockServiceA;
@Mock SomeService mockServiceB;
(有一个
doWork()
方法将检查条件并调用a或B)

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

我的意见是:

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

@Autowired @Qualifier(value="serviceB")
SomeService serviceB;
@InjectMocks ServiceCaller classUnderTest = new ServiceCaller();

@Mock SomeService mockServiceA;
@Mock SomeService mockServiceB;
然而,当我运行测试以检查服务A/B是否在正确的条件下调用时,我得到了空指针,因为模拟没有被注入


显然,这是因为同一接口上有多个依赖项(
SomeService
)。在声明模拟服务时,是否有方法指定限定符?或者我需要为依赖项设置setter并以老式方式进行设置吗?

将模拟命名为serviceA和serviceB就足够了。来自Mockito:

属性设置器注入;模拟将首先按类型解析,然后, 如果存在多个相同类型的属性,则 属性名和模拟名

在您的示例中:

@InjectMocks ServiceCaller classUnderTest;

@Mock SomeService serviceA;
@Mock SomeService serviceB;
请注意,在使用@InjectMocks时,不需要手动创建类实例

然而,我个人更喜欢使用构造函数注入依赖项。这使得在测试中注入mock变得更容易(只需使用mock调用构造函数,而无需使用反射工具或
@injectmock
(这很有用,但隐藏了一些方面))。此外,使用它可以清楚地看到被测试类需要哪些依赖项,IDE也可以生成构造函数存根

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

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

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

    ...
}
此代码可以通过以下方式进行测试:

@Mock SomeService serviceA;
@Mock SomeService serviceB;

//in a setup or test method
ServiceCaller classUnderTest = new ServiceCaller(serviceA, serviceB); 
您可以使用“name”属性定义实例,如下所示:

@Mock(name="serviceA") SomeService serviceA;
@Mock(name="serviceB") SomeService serviceB;

当您具有相同的类型依赖项时,mockito会由于相同类型的属性而停止注入依赖项。要通过以下方式参考@osiris256解决此问题:

class ServiceLayer{

   @Autowired
   @Qualifier("bean1")
   private InterfaceA typeA;  

   @Autowired
   @Qualifier("bean2")
   private InterfaceA typeB;  

}
您的测试类应为:

@RunWith(SpringRunner.class)    
class ServiceLayerTest{

  @Mock(name = "typeA")
  private InterfaceA typeA;  

  @Mock(name = "typeB")
  private InterfaceA typeB;  

  @InjectMocks
  ServiceLayer serviceLayer;

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

  // here goes your test 
  @Test
   public void test(){
     // use your when then .....
  }
}
注意:如果您使用SpringRunner并使用@MockBean,那么这将不起作用,
您必须用@Mock(name=”“)替换为@osiris256。

Brilliant!希望它能像那样简单,而且它能起作用。谢谢Szpak!!!在您可以编写的最后一行代码中:@InjectMocks ServiceCaller classUnderTest;是的,但是请阅读我回答中的文本,了解为什么我通常喜欢在测试中明确地调用构造函数。我希望通过命名
@Mock(name=“nameMatchingQualifier”)
他们可以自动匹配constructor中的
@Qualifier
,因此使用
@InjectMocks
而不是从测试中手动调用构造函数,因此,它必须使用反射来实现InjectMocks已经相当复杂了(对于新手来说,这有时会让人惊讶——例如,假设添加了一个新的构造函数参数,它可以跳过构造函数注入,并切换到字段注入,使新字段未设置-
null
)。因此,您可以在Mockito中为此创建一个票证,但团队可能不愿意实现。您能否提供任何进一步的详细信息来解释您的答案如何添加接受的答案尚未提供的任何值?如果您是在字段上自动连线,而不是构造函数(尽管这是一种糟糕的做法),这是唯一的出路