[英]Test class with nested dependencies
我正在测试具有嵌套(自动装配)依赖项的类。 该类实现用于在后端进行更改的businesslogic。 具体来说,测试应断言某个后端调用返回错误时:
我不知道后者该怎么办。 我的课看起来像这样:
public class Handler {
@Autowired
private DaoImpl dao;
@Autowired
private SpecificUtil util1;
@Autowired
private GeneralUtil util2;
@Autowired
private Helper helper;
public Response doSomethingClever(Request request) {
// calls to dao
// logic with help of util and helper classes
}
}
测试类:
public class HandlerTest {
@Spy
private DaoImpl dao;
@Mock
private SpecificUtil util1;
@Mock
private GeneralUtil util2;
@Mock
private Helper helper;
@InjectMocks
Handler handler;
@Test
public void testDoSomethingClever() {
// set up dao to fail
QueryResult error = getErrorResult();
org.mockito.Mockito.when(dao.queryBackEnd(any(SpecificQuery.class))).thenReturn(error);
// perform query
Request request = getTestRequest();
Response errorResponse = handler.doSomethingClever(request);
// verify that either:
// Response has errors - fails
// because helper classes are mocks, have not set the error
assertNotNull(response.getErrorMessage());
// the method setErrors of Response was called once - fails
//because the setError was called earlier!
Response spyResponse = Mockito.spy(errorResponse);
verify(spyResponse, times(1)).setError(anyString);
//verify no other calls are made except the queryBackEnd call - this part works
org.mockito.Mockito.verify(dao).queryBackEnd(any(SpecificQuery.class));
org.mockito.Mockito.verifyNoMoreInteractions(dao);
}
}
在Handler类中创建Response对象。 如果我检查返回的响应,则Mockito将不会记录任何交互,因为交互是在调用Mockito.spy之前发生的。
我尝试通过使用@Spy而不是@Mock使其成为集成测试。 这个想法是实例化除dao之外的所有嵌套依赖项,并获得适当的Response以测试错误。 但这是行不通的,因为某些@Autowired帮助程序和实用程序类也具有@Autowired依赖关系,并且这些嵌套的依赖关系在测试期间不会实例化。
有没有办法用Mockito将@Spy对象注入到其他@Spy对象中? 还是在这种情况下还有其他解决方案? 我可以编写自己的模拟对象吗?
单元测试应仅测试特定单元的代码(此处为Handler
类)。 这包括与依赖项进行交互。
从您在问题和评论中所写的内容来看, handle
方法的外观大致如下:
public class Handler {
@Autowired
private DaoImpl dao;
@Autowired
private Util util;
public Response doSomethingClever(Request request) {
SpecificQuery specificQuery = new SpecificQuery();
specificQuery.setSomeData(request.getSomeData());
IntermidiateResponse intermidiateResponse = dao.queryBackEnd(specificQuery);
Response response = util.processIntermidiateResult(intermidiateResult);
return response;
}
}
这里有一些要进行单元测试的交互:
Request
实例,就可以断言使用SpecificQuery
实例调用DaoImpl::queryBackEnd
方法,该实例具有将Request
对象的someData
属性设置为someData
属性 IntermidiateResponse
从返回DaoImpl::queryBackEnd
方法断言这一结果是到过Util::processIntermidiateResult
方法 Util::processIntermidiateResult
方法返回的模拟Response
,则断言这正是从handle
方法返回的内容 这样,您对Handler::handle
方法的覆盖率为100%。 如果响应处理管道中还有其他一些调用,则可以对它们进行相应的测试。
希望这能回答您的问题。 祝好运
有两种选择,一种是单独测试Handler,模拟其他所有东西。 请参阅jannis的答案 。 另一个选择是控制/模拟Handler的输入和输出,并将Handler 及其所有实用程序类视为黑匣子。
我选择了最后一个选项,因为这意味着我可以重构实用程序类和Handler类本身,并且只要我不更改Handler的功能,测试就可以成功。 这确实意味着我已经脱离了单元测试的范围,而我实际上正在做更多的集成测试。
为此,我模拟了Dao类,以便可以让它在所需的点返回错误,并可以断言在错误之后不再进行任何调用。 这是我模拟的唯一类,因此我需要将其注入到Handler中。 Springs ReflectionTestUtils可以做到这一点(我昨天不知道这件事)
然后,测试代码变得更短:
public class HandlerTest {
@Autowired
private Handler handler;
@Test
public void testDoSomethingClever() {
// set up dao to fail
Dao mockDao = org.mockito.Mockito.mock(DaoImpl.class);
QueryResult error = getErrorResult();
org.mockito.Mockito.when(dao.queryBackEnd(any (SpecificQuery.class))).thenReturn(error);
// inject the dao
ReflectionTestUtils.setField(handler, "dao", mockDao);
// perform query
Request request = getTestRequest();
Response errorResponse = handler.doSomethingClever(request);
// verify that Response has errors
assertNotNull(response.getErrorMessage());
//verify no other calls are made except the queryBackEnd call
org.mockito.Mockito.verify(dao).queryBackEnd(any(SpecificQuery.class));
org.mockito.Mockito.verifyNoMoreInteractions(dao);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.