单元测试Web服务的推荐模式

Kod*_*hor 8 rest wcf soa unit-testing web-services

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

我们应该编写发出http请求的测试并声明响应是他们应该的吗?我们是否应该只关注测试服务方法本身的内部逻辑而不是担心测试实际的请求?或者我们应该两个都做?我们应该测试什么还有其他建议吗?

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

Bro*_*ski 11

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

  1. 验收测试,你想黑盒子测试你的整个服务,并在四肢捅东西.
  2. 测试特定的WCF连线,扩展,行为等.
  3. 测试您的界面和数据成员是否正确设置.

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

注意

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

Castle.DynamicProxy.Generators.AttributesToAvoidReplicating
  .Add<ServiceContractAttribute>();
Run Code Online (Sandbox Code Playgroud)