如何使用TDD方法创建一个宁静的Web服务?

时间:2012-12-07 22:05:03

标签: c# web-services unit-testing tdd

我被赋予了一项任务,即使用WCF格式化JSON格式化,使用以下方法使用TDD方法,该方法应将产品存储为磁盘上的文本文件:

CreateProduct(Product product)
GetAProduct(int productId) 


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

创建服务及其Web方法很容易,但

您如何使用TDD完成此任务?您应该在创建SUT代码之前创建测试。

单元测试的规则说它们也应该是独立且可重复的。

我有一些困惑和问题如下:

1)我是否应该通过添加对它的引用或服务的URL来编写针对实际服务实现的单元测试(在这种情况下我必须托管和运行服务)?或两者兼而有之?

2) 我想一种方法可能只是创建一个测试方法,在其中我创建一个产品,调用CreateProduct()方法,然后调用GetAProduct()方法并断言发送的产品是我收到的产品。在TearDown()事件中,我只删除已创建的产品。

但我与上述问题的关系是

  • 它测试多个功能,因此它不是真正的单元测试。
  • 它不会检查数据是否正确存储在文件中
  • 是TDD吗?

如果我为每个Web方法创建一个单独的单元测试,然后例如调用GetAProduct()web方法,我必须将一些测试数据物理存储在服务器上,因为它不能依赖于CreateProduct()单元测试。他们应该能够独立运作。

请建议。

谢谢,

2 个答案:

答案 0 :(得分:0)

很好地回答你的问题我要做的是编写测试调用其余服务并使用类似Rhino Mocks的东西来安排(即设置对调用的期望),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();

       }

}

答案 1 :(得分:0)

我建议不要担心网络服务的终点并关注系统的行为。为了便于讨论,我将删除所有技术术语,并谈谈我认为您正在尝试解决的核心业务问题:创建产品目录。

为了做到这一点,首先要考虑产品目录的作用,而不是关于如何做的技术细节。将其作为测试的起点。

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

    [Test]
    public void allowsUpdatesToExistingProducts() {}

    [Test]
    public void allowsFindingSpecificProductsUsingSku () {}
}

我不会在这里详细介绍如何实施测试和生产代码,但这是一个起点。一旦您完成ProductCatalog生产课程,您就可以将注意力转向技术细节,例如制作网络服务和整理您的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中包含的业务逻辑,并且可能会跳过测试编组,因为它可能完全由框架完成,并且只需要很少的代码就可以将控制器绑定到产品目录中。您的里程可能会有所不同。

最后,在测试驱动目录时,我希望代码可以分成多个类,并且模拟在那里发挥作用,因此它们将进行单元测试,而不是大型集成测试。再一次,这是另一天的主题。

希望有所帮助!

布兰登