有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我希望测试的Java类(名为ServiceCaller)有以下内容:

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

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

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

如何将每个服务的模拟注入相应的变量

我的Junit有:

@InjectMocks ServiceCaller classUnderTest = new ServiceCaller();

@Mock SomeService mockServiceA;
@Mock SomeService mockServiceB;

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

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


共 (3) 个答案

  1. # 1 楼答案

    将模拟命名为serviceA和serviceB就足够了。来自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时,不需要手动创建类实例

    然而,我个人更喜欢使用构造函数注入依赖项。这使得在测试中注入mock变得更容易(只需使用mock调用构造函数,而无需使用反射工具或@InjectMocks(这很有用,但隐藏了一些方面))。此外,使用TDD可以清楚地看到测试类需要哪些依赖项,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); 
    
  2. # 2 楼答案

    当您具有相同类型的依赖项时,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

  3. # 3 楼答案

    可以使用“name”属性定义实例,如下所示:

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