Messing Around with Fluent Interfaces

I’ve recently been building a couple of very small fluent interfaces.  These have been focused on component testing, where some of their disadvantages aren’t as important.  Let me give an example:

public void PartialRecoveryFromTwoSessions() {
    When
        .SessionStartsAt("1 Jan 1990 21:25:00", s => s
            .MessagesProcessed(3, 5, 1))
        .And.SessionStartsAt("1 Jan 1990 21:35:00", s => s
            .MessagesProcessed(2, 6))
    .Then
        .RecoveryStartsFrom(4)
        .RecoveryWillSkip(5, 6);
}

Now, the great advantage of expressing your test in this fashion is that it’s quite easy for someone to look at the test and see what you mean.  However, there are a couple of disadvantages worth mentioning:

  • Although it makes your intent obvious, it doesn’t make it obvious that your intent has, in fact been satisfied.
  • Since you’ve just written a short testing framework, you really ought to write some tests for the framework itself.  That would probably involve mocking the object under test.
  • Writing this style in C# typically involves creating builder objects.  Personally, I try to avoid writing mutable objects wherever  possible, and builder objects are about as mutable as they come.
  • The overhead of creating an actual framework for testing rather discourages the practice of test-first development.

Despite this, the improved ability of the test to communicate intent makes it well worth doing.

How it works

Martin Fowler’s article gives you the abstract details of how this sort of thing works in C# and Java, but I thought it would be worth explaining the example I’ve built here.  You’ll note that there are a large number of violations of standard practice in this explanation.  That’s one of the major reasons I’m using this principally in testing code: I really don’t like the stylistic continuity from standard coding practices.

  • When is a property that creates a new CaseBuilder object.  This object also acts as the stub repository (this implementation doesn’t use a mocking framework, so all test doubles are actual physical objects).  Obviously, you’d never violate separation of concerns like that in production code.
  • SessionStartsAt is a method that creates a session and adds it to the repository.  It then returns the CaseBuilder to allow the method chaining.
  • To configure the session, you implement an action on the session.  This is a pattern I learnt from the Fluent NHibernate code base.  The advanatage of this is that you don’t need to worry about how to get back to the CaseBuilder object after you’ve finished configuring the session.
  • “And” does nothing, it just returns the builder object.  It’s only there for (natural language) readability.
  • “Then” actually performs the test and returns a CheckBuilder.  By returning a new type, you restrict what appears in auto-complete and prevent people from expressing logical nonsense in the tests.

If you need to customize how the test runs, you tend to need to insert another delegate into the system.  In general, though, I’m quite pleased with the technique.  There’s less than 300 lines for the framework outlined above, most of which is relatively trivial code of the form “set property, then return “this” “.

Technorati Tags: ,

Published by

Julian Birch

Full time dad, does a bit of coding on the side.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s