使用 lombok @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 时,Mockito when().thenReturn() 的行为不符合预期

Mis*_*aJi 2 java spring junit4 mockito lombok

我有 Spring 课说

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
class MainServiceImpl implements MainService {
    private final InternalService internalService;

    public Set<String> do(String anything) {
      Set<String> relevent = internalService.finaIntern(anything);
      return relevent;
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在编写单元测试用例如下

@RunWith(MockitoJUnitRunner.class)
class TestMainServiceImpl {

    @InjectMocks
    private MainServiceImpl service;

    @Mock
    InternalService internalService;   

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

    @Test
    public void testDo() { 
        Set<String> setData = new HashSet<>();
        setData.add("ABC");
        String a ="a";
        when(internalService.finaIntern(any(String.class))
                                  .thenReturn(setData);
        Set<String> result = service.do(a);
        assertTrue(!result.isEmpty());
    }

}
Run Code Online (Sandbox Code Playgroud)

在这里我的测试用例失败,但如果我删除的最终形式MainServiceImpl,做一个明确的@Autowired像下面

@Component
class MainServiceImpl implements MainService {
    @Autowired
    private InternalService internalService;
     .....
Run Code Online (Sandbox Code Playgroud)

在这里,我很想知道 1. 如果我删除 final 关键字,我的测试用例如何通过 2. 使用 @RequiredArgsConstructor 是否是一个好习惯,如果是,那么如何,如果否,那么为什么?

提前致谢

Ser*_*hyr 5

它与lombokSpring 和@Autowired 的组合无关@RunWith(MockitoJUnitRunner.class)MockitoAnnotations.initMocks(this);是问题所在。删除其中任何一个,行为都符合预期。你不需要他们两个。实际上MockitoAnnotations.initMocks(this);只存在于无法使用的情况下@RunWith(MockitoJUnitRunner.class),例如需要使用SpringRunner.class.

这就是它不起作用的原因。首先,您的所有对象都已实例化。因此@Mock,您的@InjectMock对象都已创建并注入到您的对象中:

下面你可以看到,新创建的模拟(mocks[0]),service里面的injectIntomock是同一个对象。

在此处输入图片说明

但是随后第二次发生初始化。所以 mockito 创建一个新@Mock对象,并尝试将它注入到您的@InjectMock对象中,该对象已经实例化。但只要它是最终的,就未能将其注入该领域。所以这是我们在第二次初始化后的内容:

在此处输入图片说明 如您所见,现在您内部的模拟对象testClassInstance和注入到被测对象的模拟是不同的。

怎么样@RequiredArgsConstructor:对我来说,按照你的方式使用它是完全可以的。