【发布时间】:2021-04-01 02:09:19
【问题描述】:
我在单元测试中使用Mockito 3.4.6,实际上,我已将 Mockito 集成到我的单元测试中并且效果很好。虽然,现在我需要优化一些单元测试,这是一个 特殊的依赖注入,注入的对象没有无参数构造函数,我尝试了@Spy 但它没用。
我的测试:我试过 1.@Spy; 2. @Spy 使用= getDtInsightApi() 设置实例; 3.@Spy和@InjectMocks,所有的测试都失败了。正如 Mockito 文档所说,它似乎不适用于这种情况。
@InjectMocks Mockito 将尝试仅通过构造函数注入来注入模拟, setter 注入或属性注入,如下所述。
如果只使用@Spy,也会抛出MockitoException:
org.mockito.exceptions.base.MockitoException:
Failed to release mocks
This should not happen unless you are using a third-part mock maker
...
Caused by: org.mockito.exceptions.base.MockitoException: Unable to initialize @Spy annotated field 'api'.
Please ensure that the type 'DtInsightApi' has a no-arg constructor.
...
Caused by: org.mockito.exceptions.base.MockitoException: Please ensure that the type 'DtInsightApi' has a no-arg constructor.
查看我的伪代码如下:
配置类:
@Configuration
public class SdkConfig {
@Resource
private EnvironmentContext environmentContext;
@Bean(name = "api")
public DtInsightApi getApi() {
DtInsightApi.ApiBuilder builder = new DtInsightApi.ApiBuilder()
.setServerUrls("sdkUrls")
return builder.buildApi();
}
}
DtInsightApi class 没有公共的无参数构造函数并通过其内部类获取实例
public class DtInsightApi {
private String[] serverUrls;
DtInsightApi(String[] serverUrls) {
this.serverUrls = serverUrls;
}
// inner class
public static class ApiBuilder {
String[] serverUrls;
public ApiBuilder() {
}
...code...
public DtInsightApi buildApi() {
return new DtInsightApi(this.serverUrls);
}
}
...code...
}
单元测试类:
public Test{
@Autowired
private PendingTestService service;
@Spy
private Api api = getDtInsightApi();
@Mock
private MockService mockService;
@Before
public void setUp() throws Exception {
// open mock
MockitoAnnotations.openMocks(this);
// i use doReturn(...).when() for @Spy object
Mockito.doReturn(mockService).when(api)
.getSlbApiClient(MockService.class);
Mockito.when(mockService.addOrUpdate(any(MockDTO.class)))
.thenReturn(BaseObject.getApiResponseWithSuccess());
}
public DtInsightApi getDtInsightApi () {
return new DtInsightApi.ApiBuilder()
.setServerUrls(new String[]{"localhost:8080"})
.buildApi();
}
@Test
public void testUpdate() {
service.update();
}
}
PendingTestService:
@Service
public class PendingTestService{
@Autowired
DtInsightApi api;
public void update() {
// here mockService isn't the object i mocked
MockService mockService = api.getSlbApiClient(MockService.class);
mockService.update();
}
}
问题:如何模拟没有no-arg构造函数的DI对象DtInsightApi。
【问题讨论】:
-
我相信要走的路是
Mockito.mock(DtInsightApi.class)。然后你存根所有调用的方法。 -
您可以尝试模拟构建器类和相关方法。因此,有了这个,您可以很好地模拟构建器的
build方法并返回一个纯粹模拟的DtInsightApi实例。顺便说一句,您提到您尝试对此进行监视,但没有成功。您注意到什么问题? -
嗨akortex91,我调试了
MockService mockService = api.getSlbApiClient(MockService.class);,发现mockService实例不是mockito代理对象。 -
@naimdjon,在
DtInsightApi api = Mockito.mock(DtInsightApi.class);之后我应该怎么做才能将它注入弹簧? -
@KDFinal 您必须使用模拟实例化服务或创建具有@Bean 注释的测试配置,该注释提供
DtInsightApi的实例。