views:

178

answers:

3

Hello again.

We are currently replacing a 20 year old C based system with a modern SOA WCF system built in .NET3.5. Our industry requires rigorous testing including good automated unit test converage. We are having issues, however unit testing our SOA system to anywhere near the extent that the C based system was unit tested.

The single biggest problem is that most of the methods in the system are actually dependant on calling into code across service boundaries, for example we are heavily data driven but we don't access the database directly within our system: we call into a WCF Data Access Service.

Running any unit tests in visual studio is almost impossible as doing almost anything results in cross service calls of some kind. If its not data access its one of the other services. I reckon we can get about 5% coverage.

I see alot of people struggle with testing SOA so I take it this is not unique to us. The thing is QA is going to question why we are not unit testing more of the system.

To be honest I see VSTS unit testing as more of a regression testing than a validation (fit for use) tool. What options are there for unit testing SOA? Is it realistic in peoples experience to achieve good coverage? Is there a way to mock a Data Access Service (or any service: NOTE we dont use WCF proxies) or do we have to explain to QA that unit testing ability has gone backwards over the last 20 years...

Any sort of suggestions are welcome, I guess this is a general opinion question.

+1  A: 

Here's my suggestion: step away from the "Unit Testing" paradigm, and work on a suite of integration tests.

I assume that your system has a front end which calls the services.

Write a test suite that actually connects to running services (in your test environment obviously) and makes the same sequence of calls as your front end does.

Your test environment would have the latest services running against an empty test database. Just like with unit tests, each test would make the calls that populates the test data with just what it needs, invoke functionality, test that the visible information now matches what it should, then clears the database again.

You may have to create one other service that services the integration tests by clearing the database on request. (Obviously, you wouldn't actually deploy that one...)

While they are not "Unit tests", you would be getting full coverage.

Andrew Shepherd
I should add that further complicating this is that alot of what we do is publish-subscribe over WCF callback contracts. Alot of things are asyncronous. That said what you have posted does make alot of sense and really we can do alot of our testing in that way.With our pub-sub model alot of "subscription updates" pushed from service to client are actually triggered by user actions (which are sent to our services as "commands messages" over WCF), so even though we are pub-sub we are also still very request reply in a way: when something is sent, we expect a reply.
MrLane
+1  A: 

It sounds like the testing you are doing now is integration tests or system tests. Where the test methods are calling external sources. To truly perform unit testing on a service you will need to somehow abstract the external calls out so you can mock (for example moq) or stub the calls to that service.

For example Code that is tightly coupled to the Data Access Service:

public class SomeSOA
{
 public bool DoSomeDataAccess()
 {
  //call the real data service
  DataService dataService = new DataService()
  int getANumber = dataService.GetANumber();
  return getANumber == 2;
 }
}

Slightly refactored to reduce coupling to the DataService

public class SomeSOA
{
 IDataService _dataService;
 public SomeSOA(IDataService dataService)
{
  _dataService = dataService;
}
public SomeSOA() :this(new DataServiceWrapper()){}
 public bool DoSomeDataAccess()
 {
  int getANumber = _dataService.GetANumber();
  return getANumber == 2;
 }
}

public DataServiceWrapper : IDataService
{
  public int GetANumber()
  {
   // call the real data service
  }
}

Now with the re-factored code you can modify your tests to use a stub that can return expected results without calling the real DataService.

[TestMethod]
public void GetANumber_WithAValidReturnedNumber_ReturnsTure()
{

  IDataService dataService = new DataServiceFake();
  SomeSOA someSoa = new SomeSOA(dataService);
  Assert.IsTrue(someSoa.DoSomeDataAccess();
}

public class DataServiceFake :IDataService
{
  public int DoSomeDataAccess()
  {
    //return a fake result from the dataService.
    return 2;
  }
}

Now granted all of this is just pseudo code, but decoupling your service from the real implamentation of the DataAccessSerive will allow you to unit test your code and not rely on a real DataAccessService for them to perform correctly.

Hope this helps and makes sense!

Mark
+3  A: 

I'd have to say that unit-testing an SOA is a lot like unit-testing anything else. If anything it should be easier because it forces you to isolate dependencies.

Unit tests shouldn't generally cross service boundaries. Really, the idea of a service is that it is completely independent and opaque. You test the service directly - not over the WCF channel, but by unit-testing the actual classes that compose the service. Once you've tested the service itself (which you should be able to get near 100% coverage), you don't need to involve it in client-side tests.

For client-side unit tests, you mock the service. WCF actually makes this very easy for you because every WCF client implements an interface; if you normally use the FooService or FooServiceSoapClient in your code, change it to use the corresponding IFooService or FooServiceSoap that the proxy class implements. Then you can write your own MockFooService that implements the same interface and use that in your client tests.

Part of what sometimes trips people up here is the idea that the service can do wildly different things depending on the specific message. However, a client test that involves the service interface should generally only be testing one or two specific messages per test, so it's easy to mock the exact request/response you need for a given client test using a tool like Rhino Mocks.

Duplex gets a little tricky but keep in mind that duplex services are supposed to be based around interfaces as well; even the MSDN example introduces an ICalculatorDuplexCallback. Callbacks will be interfaces, so just like you can mock the service methods on the client side, you can mock the client callbacks on the service side. Just have mock/fake callbacks that you use for the service unit tests.

Mark Seeman has a pretty good blog post all about Unit-Testing Duplex WCF Clients, with example code and all. You should give that a read, I think it will help you out here.

Aaronaught