簡體   English   中英

ASP.net:單元測試,依賴於Web服務代理類

[英]ASP.net: Unit testing with dependency on web service proxy class

假設我有一個類似以下的類:

public class Test{
        private RemoteDoc.Documentation docService = new RemoteDoc.Documentation();
        public Test(){}
}

因此,由於依賴於代理類,因此很難進行單元測試。 您可以通過構造函數傳遞對象,如下所示:

public class Test{
        private RemoteDoc.Documentation docService;
        public Test(RemoteDoc.Documentation serv)
        {
               docService = serv;
        }
}

現在,在單元測試中,我可以實例化Test類並將模擬對象傳遞給構造函數。 但是,此解決方案並不理想,因為現在其他類都必須了解RemoteDoc.Documentation代理類並對其有明確的引用。 什么是解決這個問題的好方法?

編輯:更清楚地說,RemoteDoc.Documentation是Web參考的代理類。 如果您使用的是salesforce.com的api,而您真正擁有的只是wsdl和disco文件,則可以將其想象為。

實際上,您建議的涉及通過構造函數傳遞依賴項的解決方案是理想的。 這是眾所周知的依賴注入(DI)模式,稱為構造函數注入

起初似乎是弱點,實際上是一種力量。 盡管確實確實每個Test類的使用者(在您的示例中)現在都必須提供代理的某種實現(我在此假設代理是接口或抽象基類),但他們可以提供該抽象的任何實現,並且不僅是您最初的想法。 恭喜: 您剛剛開設了可擴展性課程

這仍然留下了一個問題,即您將決定將哪些依賴項實際放到哪里的責任到底在哪里? 您應該在應用程序的根目錄(稱為“ 合成根目錄”)中執行此操作。 此SO答案對此進行了更詳細的說明。

您可以使用DI容器自動連線您的視線。 一些常見的DI容器是:

我喜歡RichardOD的方法。 對單元測試有用的一種改進是使用模擬對象而不是訪問實際的Web服務。 這意味着您的測試將與任何外部服務分離,並且運行速度更快。

如果代碼更改為以下形式,則可以執行以下操作:

public class Test
{        
     private RemoteDoc.IDocumentation docService;     

     // Constructor providing default for docService
     public Test()
     {
         docService = new RemoteDoc.Documentation();
     }   

     // Constructor for injection
     public Test(RemoteDoc.IDocumentation serv)       
     { 
          docService = serv;        
     }
}

然后,使用如下模擬框架創建模擬文檔對象:

...並將其傳遞給Test(RemoteDoc.IDocumentation serv)構造函數。

由於RemoteDoc.Documentation是一個具體的類,因此您可以使用部分類使其從RemoteDoc.IDocumentation繼承:

namespace RemoteDoc
{
    public interface IDocumentation
    {
        // public functions you want to mock go here
        string GetDocumentation();
    }

    public partial class Documentation : IDocumentation {}
}

我贊成馬克的做法。 為了完整性,另一個選擇如下:

public class Test
{        
     private RemoteDoc.Documentation docService;     

     // Constructor providing default for docService
     public Test()
     {
         docService = new RemoteDoc.Documentation();
     }   

     // Constructor for injection
     public Test(RemoteDoc.Documentation serv)       
     { 
          docService = serv;        
     }
}

這意味着您擁有默認的實現,並且可以選擇插入其他實現。 如果您不想使用容器,則很有用。

我過去曾經使用過兩種方法。 在開發非常規軟件時,通常使用DI容器方法是一種更好的方法。

請注意,使用WCF更加容易,因為服務合同已經是接口。 您的模擬類僅需要實現接口。

這種方法怎么樣? 您將不得不編寫更多代碼來支持代理類中的功能。 但這將為您提供單元測試的靈活性。

public interface IDocumentation
{
    // Add whatever functionality you need from RemoteDoc.Documentation
}

public class RemoteDocumnetation : IDocumentation
{
    private RemoteDoc.Documentation docService = new RemoteDoc.Documentation();

    // Implements IDocumentation 
}

public class Test{
        private IDocumentation doc;
        public Test(IDocumentation serv)
        {
               doc= serv;
        }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM