2012-12-07 136 views
3

我一直在考慮建立用TDD方式使用WCF與下面的方法JSON格式化RESTful Web服務應該將產品存儲在磁盤上的文本文件的任務:如何用TDD方法創建一個寧靜的Web服務?

CreateProduct(Product product) 
GetAProduct(int productId) 


URI Templates: 
POST to /MyService/Product 
GET to /MyService/Product/{productId} 

創建服務和其網絡方法很容易,但

你如何用TDD來完成這項任務?您應該在創建SUT代碼之前創建一個測試。

單元測試的規則說,它們也應該是獨立的和可重複的。

我有一些困惑和問題如下:

1)我應該通過增加,或對服務的URL的基準(編寫針對實際的服務實現我的單元測試在這種情況下,我必須主持並運行服務)?或兩者?

2) 我在想一種方法可能只是創建一個測試方法,我在其中創建一個產品,調用CreateProduct()方法,然後調用GetAProduct()方法並斷言發送的產品是一個我收到的。在TearDown()事件上,我只是刪除了創建的產品。

但我與上述問題是

  • 它測試一個以上的功能,因此它不是一個真正的單元測試。
  • 它不檢查數據是否正確存儲在文件上
  • 它是TDD嗎?

如果我爲每個web方法創建一個單獨的單元測試,然後例如調用GetAProduct()web方法,我必須將一些測試數據物理存儲在服務器上,因爲它不能依賴於CreateProduct()單元測試。他們應該能夠獨立運行。

請指教。

感謝,

+5

實際上,獲取URL和解析結果超出了單元測試,在我看來。單元測試應該在應用程序的類和方法級別上運行,而不是在基礎結構上運行。您還希望避免在測試中使用「真實」存儲,因爲那樣您也在測試數據庫,而不僅僅是使用數據庫的代碼。你應該閱讀有關嘲笑,有大量的信息(例如,[在SO](http://stackoverflow.com/questions/37359/what-c​​-sharp-mocking-framework-to-use)) –

+1

謝謝尼克拉斯。你說什麼是有道理的,但如果我不測試網址,我將如何測試服務接受JSON格式,或者序列化是否正確?測試網址時,必須使用真實的存儲空間。我想我必須編寫單元測試和集成測試的混合體? TDD說什麼? –

+0

我不明白TDD與此有什麼關係。它只是說你應該在實現之前在一些迭代過程中編寫測試。至於你的問題,單元測試將確保(1)你的JSON解析器工作正常(2)序列化工作正常(3)你的服務正在將正確的數據傳輸到底層(你可以使用存根檢查或模擬對象,實現與解析器/序列化器相同的接口/不管)。你也可以測試像URL解析這樣的東西,但*作爲一個獨立的模塊*。除此之外的一切都是集成測試 –

回答

0

好回答你的問題是什麼我會做的是編寫測試調用REST服務,並使用類似犀牛嘲笑安排(即設定一個期望呼叫),ACT(實際運行調用要測試的單元的代碼,並斷言你得到了你期望的結果,你可以嘲笑剩餘調用的預期結果,其餘服務從前到後的實際測試將是一個集成測試,而不是一個單元測試

因此要更清晰地進行單元測試,您需要編寫的是測試業務邏輯中實際調用其他Web服務的內容...

像這是你提出的實現(可以假裝這甚至還沒有被寫入)

public class SomeClass 
    { 
     private IWebServiceProxy proxy; 
     public SomeClass(IWebServiceProxy proxy) 
     { 
      this.proxy = proxy; 
     } 

     public void PostTheProduct() 
     { 
      proxy.Post("/MyService/Product"); 
     } 

     public void REstGetCall() 
     { 
      proxy.Get("/MyService/Product/{productId}"); 
     } 
    } 

這是你可能會考慮寫一個測試。

[TestFixture] 
    public class TestingOurCalls() 
    { 
     [Test] 
     public Void TestTheProductCall() 
     {  
     var webServiceProxy = MockRepository.GenerateMock<IWebServiceProxy>(); 
     SomeClass someClass = new SomeClass(webServiceProxy); 

     webServiceProxy.Expect(p=>p.Post("/MyService/Product")); 

     someClass.PostTheProduct(Arg<string>.Is.Anything()); 

     webServiceProxy.VerifyAllExpectations(); 

     } 

}

0

我建議不擔心Web服務端點和專注於系統的行爲。爲了討論這個話題,我會放下所有的技術術語,並談論我認爲您想要解決的核心業務問題:創建產品目錄。

爲了做到這一點,首先考慮產品目錄的作用,而不是關於如何去做的技術細節。用它作爲測試的起點。

public class ProductCatalogTest 
{ 
    [Test] 
    public void allowsNewProductsToBeAdded() {} 

    [Test] 
    public void allowsUpdatesToExistingProducts() {} 

    [Test] 
    public void allowsFindingSpecificProductsUsingSku() {} 
} 

我不會詳細討論如何在這裏實現測試和生產代碼,但這是一個起點。一旦生成了ProductCatalog生產課程,您可以將注意力轉向諸如製作Web服務和編組JSON等技術細節。

我不是一個.NET傢伙,所以這將主要是僞代碼,但它可能會看起來像這樣。

public class ProductCatalogServiceTest 
{ 
    [Test] 
    public void acceptsSkuAsParameterOnGetRequest() 
    { 
     var mockCatalog = new MockProductCatalog(); // Hand rolled mock here. 
     var catalogService = new ProductCatalogService(mockCatalog); 

     catalogService.find("some-sku-from-url") 

     mockCatalog.assertFindWasCalledWith("some-sku-from-url"); 
    } 

    [Test] 
    public void returnsJsonFromGetRequest() 
    { 
     var mockCatalog = new MockProductCatalog(); // Hand rolled mock here. 
     mockCatalog.findShouldReturn(new Product("some-sku-from-url")); 
     var mockResponse = new MockHttpResponse(); // Hand rolled mock here. 

     var catalogService = new ProductCatalogService(mockCatalog, mockResponse); 

     catalogService.find("some-sku-from-url") 

     mockCatalog.assertWriteWasCalledWith("{ 'sku': 'some-sku-from-url' }"); 
    } 
} 

您現在已經測試了端到端,並且測試驅動了整個事情。我個人會測試驅動ProductCatalog中包含的業務邏輯,並且可能會跳過測試編組,因爲它很可能全部由框架完成,無需將代碼綁定到產品目錄中。你的旅費可能會改變。

最後,在測試驅動目錄時,我期望代碼被分成多個類,並且模擬會在那裏發揮作用,因此它們將被單元測試,而不是大集成測試。再次,這是另一天的話題。

希望有幫助!

布蘭登