![](/img/trans.png)
[英]How do I instantiate an unirest HttpResponse<JsonNode> for my mock?
[英]How do I mock objects that I can't instantiate in my tests?
我在我的測試中使用EasyMock來模擬對象。 但是,我如何模擬在我的代碼中的其他位置創建的對象? 查看以下psudo代碼。 我想模擬WebService#getPersonById,我該怎么做?
public class Person {
public Person find(int id) {
WebService ws = new WebService();
return ws.getPersonById(id);
}
}
public class PersonTest {
testFind() {
// How do I mock WebService#getPersonById here?
}
}
如果您使用控制和依賴注入的反轉來連接您的服務,模擬通常很有效。 所以你的人應該是這樣的
public class Person() {
WebService ws = null;
// or use setters instead of constructor injection
Persion(WebService ws) {
this.ws = ws;
}
public Person find(int id) {
return ws.getPersonById(id);
}
}
希望很明顯,通過這個更改,您現在可以為WebService創建一個模擬和模擬控件,並將其插入到您的測試中,因為當您創建要測試的Person時,您可以將模擬傳遞給構造函數(或setter)如果你去那條路)
在您的真實環境中,IoC容器將注入真正的Web服務。
現在,如果你不想處理所有這些IoC的東西,你需要做的就是將你的web服務與你的Person分開(應該調用PersonService或者其他東西,而不僅僅是Person,它表示實體)。 換句話說,編寫代碼的方式只能使用一種類型的WebService。 你需要這樣做,所以Person只需要某種類型的WebService,而不是你硬編碼的特定類型。
最后,在編寫的代碼中,WebService是一個類,而不是一個接口。 WebService應該是一個接口,您應該進行某種實現。 EasyMock適用於界面; 它可能能夠模擬具體的類(自從我實際使用它以來已經有一段時間了),但作為一個設計原則,你應該指定所需的接口,而不是具體的類。
使用EasyMock(或大多數其他模擬API)無法做到這一點。 另一方面,使用JMockit,這樣的測試將非常簡單和優雅:
public class PersonTest
{
@Test
public testFind(@Mocked final WebService ws) {
final int id = 123;
new NonStrictExpectations() {{
ws.getPersonById(id); result = new Person(id);
}};
Person personFound = new Person().find(id);
assertEquals(id, personFound.getId());
}
}
因此,每當我們遇到無法首先編寫單元測試的情況時,我們就不能自動斷定測試中的代碼是不可測試的並且需要重構。 有時會出現這種情況,但肯定並非總是如此。 也許問題不在於測試中的代碼,而是在使用的特定模擬工具的限制中。
我想你錯過了一個更大的問題。 測試的難點在於試圖告訴你一些事情,即擁有一個Person
對象(域的一部分)也使用遠程服務來查找自身的更多實例(系統的一部分)正在混淆問題。 將Person
的獲取與Person
對象分開,最終會得到更干凈,更便攜的代碼。
不要混淆立即的便利性(我手上有一個Person
對象,所以我會用它來獲得更多)具有可維護性。
您可以嘗試使用PowerMock whenNew方法
https://github.com/jayway/powermock/wiki/MockitoUsage#how-to-mock-construction-of-new-objects
更多例子 - http://www.programcreek.com/java-api-examples/index.php?api=org.powermock.api.mockito.PowerMockito
你的代碼可能看起來像 -
whenNew(WebService.class).withAnyArguments().thenReturn(yourMockInstanceToWebServiceClass);
首先你需要通過注入來使ws
成為模擬。
public abstract class Person() {
public Person find(int id) {
WebService ws = createWebService();
return ws.getPersonById(id);
}
protected abstract WebService createWebService();
}
然后你可以將它放入並使用EasyMock.expect來設置返回
public class PersonTest() {
testFind() {
WebService mock = EasyMock.createMock(WebService.class);
Person p = new Persion() {
protected WebService createWebService() {
return mock;
}
}
EasyMock.expect(mock.getPersonById()).andReturn(dummyValue);
//Test code
}
}
你還需要一個PersonImpl
來擁有真正的create方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.