我有春课说
@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;
}
}
我正在编写单元测试案例如下
@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());
}
}
此处我的测试用例失败了,但是如果我从主要服务中移除最终形式并执行明确的 @Autowired ,如下所示
@Component
class MainServiceImpl implements MainService {
@Autowired
private InternalService internalService;
.....
我很想知道 1.如果删除final关键字,我的测试用例如何通过? 2.使用@RequiredArgsConstructor是一个好习惯,如果是,那么如何,如果没有那么为什么呢?
提前致谢
答案 0 :(得分:1)
它与lombok
和Spring @Autowired
无关
@RunWith(MockitoJUnitRunner.class)
和MockitoAnnotations.initMocks(this);
的组合是个问题。删除其中任何一个和行为是预期的。你不需要他们两个。实际上,MockitoAnnotations.initMocks(this);
仅适用于无法使用@RunWith(MockitoJUnitRunner.class)
的情况,例如,如果您需要使用SpringRunner.class
。
这就是为什么它不起作用。
首先实例化您的所有对象。因此,您的@Mock
都已创建并注入@InjectMock
对象:
下面您可以看到,mocks[0]
和service
内的新创建模拟(injectInto
),mock
是同一个对象。
然后初始化第二次发生。
因此,mockito会创建一个新的@Mock
对象,并尝试将其注入已经实例化的@InjectMock
对象中。但只要它是最终的,它就无法将它注入现场。
所以这是我们在第二次初始化后得到的结果:
如您所见,现在testClassInstance
内部的模拟对象和注入测试对象的模拟是不同的。
@RequiredArgsConstructor
怎么样:对我来说,以你的方式使用它是完全可以的。
答案 1 :(得分:0)
这就是您的测试用例的样子。您不应该使用
MockitoAnnotations.initMocks(this)
在将@InjectMock用于要测试的类时。这适用于@AllArgConstructor。
@RunWith(MockitoJUnitRunner.class)
class TestMainServiceImpl {
@InjectMocks
private MainServiceImpl service;
@Mock
InternalService internalService;
@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());
}
}
尝试使用上述方法为@allArgConstructor和@RequiredArgConstructor编写测试用例。如果该方法有效,则可以尝试以下逻辑。
如果您在类中仅使用@Data批注(lombok.Data),则将生成仅具有强制性(最终)字段的构造函数。这是因为数据暗示了RequiredArgsConstructor。示例:
@Data
@Component
class MainServiceImpl implements MainService {
private final InternalService internalService;
}
@Builder注释为我们生成MainServiceImpl类,可帮助我们创建新的MainServiceImpl
@Data
@Builder
@Component
class MainServiceImpl implements MainService {
private final InternalService internalService;
}