[英]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.