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.
A unit test usually covers one call to a function or one way to use a class. A unit test is usually the first “user” of your code. Some test methodologies even require you to write the test before the implementation of the actual application code. Unit tests can be used in both backend and frontend development.
I have found testing web services, specifically WCF client and server, useful on top of regular unit testing in the following scenarios:
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>();
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With