Tuesday, March 11, 2008

BDD in Practice - Mocking

Some of the articles on BDD put a heavy emphasis on mocking and outside-in development.

However so far the discussions on the BDD group seem to have left me feeling that when to mock is just as much of an issue in BDD as it is in TDD. Having said that as I try BDD I'm making sure I also spend the time to think about the ways I use mocking, just to formalize my thoughts.

Some of this is just my unordered thoughts, just stuff I'm thinking as I write the specifications using BDD. I've broken it down to sections based on the reasons I'm mocking.

Mocking As A Design Technique

I've been trying to do some outside-in style mocking as I go, I've discussed this in an earlier post but I am finding that thinking about collaborations (for Services at least) is quite an interesting technique. I've tried it in the past and didn't like it too much, but I think I'm now at a stage where I'll try to work it in to my normal practices.

I think I'm using the technique naively though. For example I ended up writing up-front mocking tests for an XmlFileBasedSender which takes in a DTO and ensures its packaged as XML and put in a suitable file. I blindly followed the technique but ended up with what I consider to be a pretty silly design:

public XmlFileBasedSender(IXmlFileNameProvider fileNameProvider, IConfigurationService xmlConfigurationService,
IFileSystem fileSystem, INotificationToXmlConverter notificationMapper)

To me INotificationToXmlConverter and IXmlFileNameProvider are just small lightweight strategy/helper/policy classes where as the other two are meaningful abstractions (especially as with them I'm wrapping built in .NET framework functionality). I'd think this style of constructor is more meaningful:

public XmlFileBasedSender(IConfigurationService xmlConfigurationService, IFileSystem fileSystem)

To be fair this isn't a problem with the technique, I've probably just gone overboard and at mockobjects.com Steve Freeman was good enough to point out that he might have just written an integration test for the service and might have encapsulated the little policy classes.

Of course even if I do just have XmlFileBasedSender create the instance of NotificationToXmlConverter in the constructor I might want to stub out NotificationToXmlConverter. In that case I'm stubbing for convenience rather than to use it as a design technique, but I think that's OK (especially since we use TypeMock).

I'm also not planning to use this technique all the time, I think state based testing is still often the way to go and that in many cases I'll stub rather than mock but that's not to say that this technique doesn't have its place. I especially liked using it in combination with integration tests. So after writing interaction tests for XmlFileBasedSender I wrote tests for each of the dependencies and then wrote a single integration test for XmlFileBasedSender (at which point I discovered I'd forget to create a class implementing IClock).

Finding the balance between mocking/state tests and between integration/unit tests is something I'll continue to think about, though presumably never coming to a conclusion on.

Mocking/Stubbing Out Dependencies

I needed to mock out calls to DateTime.Now and File.Create, using TypeMock to mock these would not be a good idea and anyway I'm happy enough to wrap in these cases (though wrapping DateTime.Now is a little irritating). There's lots out there about wrapping like this but essentially I ended up with tests like this (using string based mocking because I'm using the free version of TypeMock for the example):

public void Current_time_retrieved_from_clock()
#region Setup Expectations

Mock mockClock = MockManager.MockObject(typeof(IClock));
mockClock.ExpectGet("Now", DateTime.Now);

IClock clock = (IClock)mockClock.MockedInstance;


Technically I guess this is mocking for design, but even if I wasn't using mocking as a design technique I'd still need to wrap the file system and clock just to allow me to stub them out.

Mocking To Make Granular Testing Easier

ClientMapper uses a ClientFeeDestinationMapper so I've written tests for the ClientFeeDestinationMapper and then written one test that proves that the ClientMapper interacts with the ClientFeeDestinationMapper. This test was not about working out role interfaces so this is not me using mocking as a design technique and I just used TypeMock to mock out the concrete ClientFeeDestinationMapper.

One problem with this is that the tests (including the state ones) are very granular so any change means re-writing them. For example I plan to try using Otis (XML based object-object mapping) again, at which point ClientFeeDestinationMapper will probably disappear and ClientMapper will do everything (everything being kicking off the mapping process). Now in order to do that I first need to re-write my tests, which is a pain but not really related to the fact that I'm mocking or to BDD.

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

No comments:

Post a Comment