Saturday, February 02, 2008

Test Spy - Replacing Services When Testing The Domain

At the recent discussion of mocking at ALT.NET UK we discussed using test spies.

We actually make good use of test spies now and they have some advantages. Let me give you an example where they come in handy. Our domain classes occassionally need to contact external services, interfaces implemented by these services are put in the domain (seperated interface) with the implementations available to the domain using a Service Locator.

What do to when testing though, we have maybe 1% of the the tests where we need to setup a mock version of the service and the rest don't care about the service so they can run with a do-nothing stub.

However if we register a mock version of the service with the Service Locator and if we forget to cleanup propely then that mock service will affect other tests. Its also painful having to put the stub service back in after you are doing using the mock.

The solution, suggested by one of my colleagues, is simple. We don't ever mock the service but instead we use a test spy. We register the Test Spy with the Service Locator in a method tagged with AssemblyInitializeAttribute so it gets run before any tests in that assembly.

All the normal tests run normally, and if they in some way cause the system to interact with the test spy then the interaction happens totally silently, for example maybe the test spy logs the interaction by adding an item to an internal collection.

So what about the 1% of the tests that really want to test against the test spy (the tests that might otherwise have used a mock). Well in the test fixture initialization we reset the test spy then at the end of each test we ask the test spy what calls it received and verify that they were what we expected.

This works a treat, really simple solution that makes the tests very easy to write.

NOTE - When to call services from the domain
The comment from Andreas made me realize that I didn't say when I think a domain class should talk to a service.

Normally I avoid these sorts of dependencies in order to keep the domain code clean, simple and easily testable. However for cross cutting concerns like logging/dirty tracking an AOP based approach (see my PostSharp posts) where we introduce the code that calls the service is very clean.

In particular this works because for those cases we can have the domain class contact the (infrastructure) Service but we don't care about any return values, hence the applicability of a Test Spy.

Share This - Digg It Save to del.icio.us Stumble It! Kick It DZone

2 comments:

  1. Hi!

    We are using the same setup as you -> interfaces to external services are placed in our Domain - namespace. These services are implemented in a "ServiceAgents"-project. But we are always letting our service-layer (Fowler pattern) interact with those External Services. I have a feeling that it sometimes would be better to let our Domain-object interact direct with thoose services (like you describe in the post). I think the way we do it is an effect of us using Windsor for DI and we are not using DI for our Domain-objects. So it's easier for us to inject our "ServiceAgents" into our service-layer. What are your reccommendation? should we move to a more "domain object should interact with external-services directly"-way of doing things?

    ReplyDelete
  2. To be honest I think your approach sounds sensible.

    Normally we avoid having the domain classes talk to services (which to use includes repositories). Doing this creates simpler code thats easier to test.

    However sometimes you do want to have the domain classes talk to services. In particular for cross cutting conerns such as logging/dirty tracking.

    In those cases I think having the domain classes talk to the service is OK, not least as they will call the service but not expect/get any return value and we can use AOP to avoid having to write the code that calls the service. The result is that you can use a Test Spy whilst testing and the call to the service does not complicate the domain objects, which is great.

    In general though I prefer avoiding designs where a domain class goes to a service for information it needs, but if you ask on the DDD forum you would definitely find people who do have entities contacting services.

    Hope this helped a little, sorry I couldn't give definitive answers though! :)

    ReplyDelete