Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
473 views
in Technique[技术] by (71.8m points)

wcf - Recommended patterns for unit testing web services

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.

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...