2012-08-30 175 views
3

下面的using會擊中一個我不想實際擊中的外部資源。我想測試someResult以及使用它的代碼,但是每次運行我的單元測試時,此代碼仍會嘗試打擊真正的Web服務。我如何使用moq來僞造真正的Web服務調用,但是不能模擬使用中的其他代碼?Moq - 如何模擬Web服務調用?

public IMyInterface.SomeMethod() 
{  
    // hits a web service 
    using (mySoapClient client = new mySoapClient()) 
    { 
      var someResult = client.DoSomething(); 
     ... 
     ... 
    } 
} 


[TestMethod()] 
public void SomeMethodTest() 
{ 
    IMyInterface target = new MyInterface(); 
    target.SomeMethod(); 

    // Assert.... 
} 

回答

10

你需要從消費者

public class ClassIWantToTest 
{ 
     public ClassIWantToTest(IServiceIWantToCall service) {} 

     public void SomeMethod() 
     { 
      var results = service.DoSomething(); 
      //Rest of the logic here 
     } 
} 

現在你可以使用最小起訂量嘲笑IServiceIWantToCall爲了測試你首先得的SomeMethod

1

邏輯分離的Web服務實現能夠注入Web服務。在SomeMethod()中創建一個新的「緊密耦合」方法到生產代碼;你不能動態地告訴它創建一個不同於mySoapClient的東西。

由於您想創建並銷燬它們,我可能會建議您要測試的代碼接受Func<IMySoapClient>作爲方法參數或作爲構造函數參數。這將是這個樣子:

public IMyInterface.SomeMethod(Func<IMySoapClient> clientFactory) 
{  
    // hits a web service 
    using (mySoapClient client = clientFactory()) 
    { 
      var someResult = client.DoSomething(); 
     ... 
     ... 
    } 
} 

...或:

public class MyClass:IMyInterface 
{ 
    private Func<IMySoapClient> MySoapClientFactoryMethod; 

    public MyClass(Func<IMySoapClient> clientFactoryMethod) 
    { 
     MySoapClientFactoryMethod = clientFactoryMethod; 
    } 

    ... 

    public IMyInterface.SomeMethod() 
    {  
     // hits a web service 
     using (mySoapClient client = MySoapClientFactoryMethod()) 
     { 
      var someResult = client.DoSomething(); 
      ... 
      ... 
     } 
    } 
} 

現在,當你創建你想測試對象,定義生成的適當起訂量模擬功能Soap服務,它具有您從真實客戶端期望的行爲而沒有副作用(包括能夠告訴客戶端的代碼Dispose()d),並將該函數傳遞到您所需的類或方法中測試。在生產中,您可以簡單地將函數定義爲()=>new mySoapClient(),或者您可以設置IoC框架並將mySoapClient註冊爲IMySoapClient,然後註冊MyClass;大多數IoC框架都足夠聰明,可以將代理看作參數並生成注入已註冊依賴項的方法。

+0

哦,你能告訴我Func <>的用途嗎?我對它並不熟悉 –

+0

'Func '是一個內置類型,它擁有一個委託(一個指向方法的「指針」),它不接受任何參數並返回泛型類型的對象(在你的情況中,你想要肥皂客戶端)。閱讀通過C#傳遞的委託;它是語言和框架的一個非常強大的功能。 – KeithS

+0

在單元測試中,我嘲笑單元測試的響應對象。在響應對象中,我想通過嘲諷爲屬性中的一個賦值。我如何實現這個 – ravithejag

1

要添加到醬菜的答案,我創建了一個interface爲我目前的服務電話IService。然後我創建了一個ServiceMock類,它繼承了接口並添加了一個名爲_service的全局變量。在構造函數中我實例模擬服務,並設置了接口的所有方法這樣:

public class ServiceMock : IService 
{ 
    Mock<IService> _serviceMock; 

    public ServiceMock() 
    { 
     _serviceMock = new Mock<IService>(); 

     _serviceMock.Setup(x => x.GetString()).Returns("Default String"); 

     SomeClass someClass = new SomeClass(); 
     someClass.Property1= "Default"; 
     someClass.Property2= Guid.NewGuid().ToString(); 

     _serviceMock.Setup(x => x.GetSomeClass()).Returns(someClass); 
    } 

    public string GetString() 
    { 
     return _serviceMock.Object.GetString(); 
    } 

    public License GetSomeClass() 
    { 
     return _serviceMock.Object.GetSomeClass(); 
    } 
} 

你再注入這個類到你的代碼,而不是實際的Web服務。它會返回你設置的值返回。您現在可以測試而不依賴於您的Web服務。