单元测试 Web 服务的推荐模式 [英] Recommended patterns for unit testing web services

查看:48
本文介绍了单元测试 Web 服务的推荐模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们即将开始构建面向服务的框架 (SOA),该框架肯定会涉及大量细粒度的 Web 服务(WCF 中的 REST).我们在对客户端和服务器端代码库进行单元测试方面非常严格,但是我们在单元测试 Web 服务方面没有太多经验.我们确实在寻求有关应在何处编写测试的指导以及关于在对我们的服务进行单元测试时使用何种方法的建议.

We are about to begin architecting a service oriented framework (SOA) which will certainly involve a high number of of granular web services (REST in WCF). We've been quite disciplined in unit testing our client and server-side code base, however we don't have much of any experience in unit testing web services. We're really looking for guidance as to where the tests should be written and recommendations on what approach to use when unit testing our services.

我们是否应该编写测试来发出 http 请求并断言响应是它们应该的样子?我们是否应该只专注于测试服务方法本身的内部逻辑,而不必担心测试实际请求?还是我们应该两者都做?对于我们应该测试的内容,还有其他建议吗?

Should we write tests that make http requests and assert that the responses are what they should be? Should we focus on just testing the internal logic of the service methods themselves and not worry about testing the actual requests? Or should we do both? Are there any other recommendations for what we should be testing?

我们真的在寻找一些解释和指导,并且非常感谢我们能得到的任何建议.

We're really looking for some explanation and guidance and would truly appreciate any advice we can get.

推荐答案

我发现测试 Web 服务,特别是 WCF 客户端和服务器,在以下场景中在常规单元测试之上非常有用:

I have found testing web services, specifically WCF client and server, useful on top of regular unit testing in the following scenarios:

  1. 验收测试,您希望对整个服务进行黑盒测试,并在极端情况下进行测试.
  2. 测试特定的 WCF 连接、扩展、行为等.
  3. 测试您的界面和数据成员设置是否正确.

大多数时候,我尝试使用带有基本 http 的非常基本的设置并将所有内容连接到代码中.除非我是集成或验收测试,否则我不会针对服务器测试客户端,而是模拟其中一个,以便我可以单独测试另一个.以下是我如何测试 WCF 客户端和服务的示例:

Most of the time I try to use a very basic setup with basic http and wire everything up in the code. Unless I am Integration or Acceptance testing I don't test the client against the server, instead I mock one of them so that I can test the other in isolation. Below are examples of how I test WCF clients and services:

public static ServiceHost CreateServiceHost<TServiceToHost>(TServiceToHost serviceToHost, Uri baseAddress, string endpointAddress)
{
    var serviceHost = new ServiceHost(serviceToHost, new[] { baseAddress });

    serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
    serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;

    serviceHost.AddServiceEndpoint(typeof(TServiceToHost), new BasicHttpBinding(), endpointAddress);

    return serviceHost;
}

//Testing Service

[TestFixture]
class TestService
{
    private ServiceHost myServiceUnderTestHost;
    private ChannelFactory<IMyServiceUnderTest> myServiceUnderTestProxyFactory;
    [SetUp]
    public void SetUp()
    {
        IMyServiceUnderTest myServiceUnderTest = new MyServiceUnderTest();
        myServiceUnderTestHost = CreateServiceHost<IMyServiceUnderTest>(myServiceUnderTest, new Uri("http://localhost:12345"), "ServiceEndPoint");
        myServiceUnderTestHost.Open();

        myServiceUnderTestProxyFactory = new ChannelFactory<IMyServiceUnderTest>(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345/ServiceEndPoint")); 
    }

    [TearDown]
    public void TearDown()
    {
        myServiceUnderTestProxyFactory.Close();
        myServiceUnderTestHost.Close();
    }

    [Test]
    public void SomeTest() 
    {
        IMyServiceUnderTest serviceProxy = myServiceUnderTestProxyFactory.CreateChannel();

        serviceProxy.SomeMethodCall();
    }
}

//Testing Client

[TestFixture]
class TestService
{
    private ServiceHost myMockedServiceUnderTestHost;
    private IMyServiceUnderTest myMockedServiceUnderTest;

    [SetUp]
    public void SetUp()
    {
        myMockedServiceUnderTest = Substitute.For<IMyServiceUnderTest>(); //Using nsubstitute
        myServiceUnderTestHost = CreateServiceHost<IMyServiceUnderTest>(myMockedServiceUnderTest, new Uri("http://localhost:12345"), "ServiceEndPoint");
        myServiceUnderTestHost.Open();
    }

    [TearDown]
    public void TearDown()
    {
        myServiceUnderTestHost.Close();
    }

    [Test]
    public void SomeTest() 
    {
        //Create client and invoke methods that will call service
        //Will need some way of configuring the binding
        var client = new myClientUnderTest();

        client.DoWork();

        //Assert that method was called on the server
        myMockedServiceUnderTest.Recieved().SomeMethodCall();
    }
}

注意

我忘了提到,如果您想使用任何使用城堡动态代理的东西来模拟 WCF 服务,那么您需要防止 ServiceContractAttribute 被复制到模拟中.我有一篇关于此的博客文章,但基本上你注册了在创建模拟之前,将属性设置为一个以防止复制.

I had forgot to mention that if you want to mock a WCF service using anything that uses castles dynamic proxy then you will need to prevent the ServiceContractAttribute from being copied to the mock. I have a blog post on this but basically you register the attribute as one to prevent from replication before you create the mock.

Castle.DynamicProxy.Generators.AttributesToAvoidReplicating
  .Add<ServiceContractAttribute>();

这篇关于单元测试 Web 服务的推荐模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆