Recommended patterns for unit testing web services

可紊 提交于 2019-11-27 20:51:26
Bronumski

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

  1. Acceptance testing where you want to black box test your whole service and poke things in at the extremities.
  2. Testing a specific WCF wire up, extension, behavior, etc.
  3. Testing that your interface and your data members are setup correctly.

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();
    }
}

NOTE

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>();
Sergio Romero

Well basically I think that you need to have a two part test strategy.

The first part would be true unit tests, which would involve testing the classes completely independent of any web request ... as the main definition of a unit test is one that runs without the need of extra environments or setups other than the ones in the test itself.

So you would create unit test projects, in which you would instantiate the code classes of your WCF services to make sure the logic is correct, in much the same way that you test the rest of your classes.

The second part would be a set of integration tests, which would test your application in an end-to-end fashion. Of course, here you need the whole enchilada, web server, database, and so forth.

This way you know that your logic is accurate and also that your application works.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!