2011-01-26 33 views
9

我使用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? 
    } 
} 

回答

0

我改用JMockit代替。它支持嘲笑一個類的所有實例。

9

如果您使用控制和依賴注入的反轉來連接您的服務,那麼嘲笑通常效果不錯。所以,你的人應該像

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。你需要這樣做,所以人只需要一些類型的WebService,而不是你已經硬編碼的具體的一個。

最後,在編寫的代碼中,WebService是一個類,而不是一個接口。 WebService應該是一個接口,你應該進行某種實現。 EasyMock與接口配合良好;它可能會嘲笑具體類(自實際使用它之後已經有一段時間了),但作爲一個設計原則,您應該指定所需的接口,而不是具體的類。

+0

+1 - 這是幾乎一模一樣我在我的(現在刪除的)答案中添加了什麼。 – 2011-01-26 16:58:51

+0

+1好的答案。成爲老師的方式。 – jwir3 2011-01-26 17:08:44

0

你們首先需要製作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有真正的創建方法。

1

我想你錯過了一個更大的問題。測試的難點在於試圖告訴你一些事情,即有一個Person對象(域的一部分)也使用遠程服務來查找自己的更多實例(系統的一部分)正在混淆關注。從Person對象中分離得到Person,最終得到更清潔,更便攜的代碼。

不要混淆即時便利(我手裏有一個Person對象,所以我會用它來獲得更多)的可維護性。

3

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()); 
    } 
} 

所以,每當我們碰到其中一個單元測試不能在第一次寫入的情況下,我們不能自動斷定被測試的代碼是不可測試的,需要重構。有時候會是這種情況,但肯定不總是如此。也許這個問題不在被測代碼中,而在於正在使用的特定模擬工具的侷限性。

相關問題