Freekshow

September 3, 2008

Unit testing part 3: Design for testability

Filed under: .Net,Microsoft,Unit Testing — Freek Leemhuis @ 11:20 am

This is part 3 in a series of posts about unit testing using Visual Studio. Part 1 and part 2 focused mainly on the MS Test environment within Visual Studio.

When writing unit tests, whether one subscribes to Test Driven Development practices or not, often forces one to consider the design of the code under test. This is probably where the term ‘Design for testability’ comes from: not all code is easily testable, and you should therefore design your code so it can easily be tested. I’ve always found the term strange, as the ultimate purpose of code is not that it is tested, but that it works and is maintanable. If you can manage loose coupling through OO principles such as the Single Reponsibilty Priciple and the Open Closed Principle, then the code is testable as a result of good design.

Or, as Uncle Bob says:

“The act of writing a unit test is more an act of design than of verification”

Having said that, what is generally meant by design for testability?

Consider the following class:

public class Clown
{
   public void TellAJoke()
    {
       Joke joke = new JokeRepository().GetRandomJoke();
       Console.WriteLine(joke.question);
       Console.Read();
       Console.WriteLine(joke.punchline);
       DrumRoll.Play();
   }
}

Just a few lines of code, and we’re already in a pickle. The code is not easily testable, and the problem is tight coupling. You can not test the TellAJoke method without also invoking the JokeRepository, Joke and DrumRoll class.

The GoF : Programming too an interface, not an implementation

(It’s actually in the first chapter, so you might catch it just before you fall asleep :-))

Let’s take this advise to heart and do some refactoring:

public class Clown
{
    ISoundEffect _soundeffect;
    IDisplay _display;
    public Clown(IDisplay display, ISoundEffect soundeffect)
    {
        _soundeffect = soundeffect;
        _display = display;
    }
    public void TellAJoke(IJoke joke)
    {
        _display.Show(joke.question);
        _display.Show(joke.punchline);
        _soundeffect.Play();
    }
}

We have defined interfaces for Joke, Display and Soundeffect. We can therefore call on the might of polymorphism if we want to use alternative methods of displaying text or using sound effects (we may want to switch to trumpets in a future iteration!). In this refactoring we are using dependancy injection to remove the coupling with Drumroll(ISoundeffects) and Console (IDisplay) by adding them as an argument to the constructor.

Note that we have also defined an interface for Joke, and added the joke as an argument to be passed into the method. Because our JokeRepository retrieves jokes from a database backend, we can not really use the repository in testing: we want to keep our tests lean and mean, and that means no database trips!

We can for the purpose of testing the TellAJoke method now subsitute the IJoke parameter with our own stub:

[TestMethod]
public void Clown_TellAJoke_Test()
{
    Clown pipo = new Clown(new ConsoleDisplay(), new DrumRoll());
    //create Joke stub
    Joke jokeStub = new Joke
    {
        question = "How many developers does it take to change a lightbulb?",
        punchline = "They won't. It's a hardware problem"
    };
    //redirect console output
    var  writer = new StringWriter();
    Console.SetOut(writer);
    //call the method under test
    pipo.TellAJoke(jokeStub);
   
    string output = writer.ToString();
    Assert.IsTrue(output.Contains(jokeStub.question));
    Assert.IsTrue(output.Contains(jokeStub.punchline));
   
}

Note that we are still using the console as the method to display text, but if we decide to change that, all we would need to do is implement the IDisplay interface on an alternative implementation. The key here is that we don’t have to change our Clown class to change the implementation of display or soundeffect.

Are you mocking to me?

So what about mocking? What’s that all about? The seminal reference in this regard is Martin Fowler’s article Mocks aren’t stubs, where he explains the difference between the two. Basically, if you are using stubs you’re usually testing state, whereas mocks allow you to test the interaction between objects.

Where we have in the previous example used a stub for the Joke class, we have left out tests for the soundeffect. What we would like to test is that the soundeffect sounds when delivering the punchline.  Let’s create a stub to substitute the soundeffect – we don’t want actual sound effects when running our unit tests, fun as that might be…

 

public class SoundEffectStub:ISoundEffect
{
    public void Play()
    {
        Console.WriteLine("Sound!");
        Console.Read();
    }
}

And we could test that the ‘sound’ gets played by redirecting the console output as before. However, we are testing state, and state that is introduced by our stub. An alternative here is to use a mocking framework that will allow us to test the interaction of these objects. The only thing we want to test is that the soundeffect gets played, and it’s for this kind of behavior verification that mocking frameworks really shine.

Typemock is a popular mocking framework in the .Net space, and we can use it for our little example as so:

 [TestMethod]
public void Clown_TellAJoke_Test()
{
    MockManager.Init();
    Mock mockSound = MockManager.Mock(typeof(SoundEffectDrumRoll));
    Clown pipo = new Clown(new ConsoleDisplay(),new SoundEffectDrumRoll());

    //create Joke stub
    Joke jokeStub = new Joke
    {
        question = "How can you tell when a programmer has had sex?",
        punchline = "When he's washing the pepper spray out of his eyes."
    };

    //redirect console output
    var  writer = new StringWriter();
    Console.SetOut(writer);

    //set expectations
    mockSound.ExpectCall("Play");

    //call the method under test
    pipo.TellAJoke(jokeStub);
   
    string output = writer.ToString();
    Assert.IsTrue(output.Contains(jokeStub.question));
    Assert.IsTrue(output.IndexOf(jokeStub.punchline) > output.IndexOf(jokeStub.question));

    mockSound.Verify();

}

Typemock is different from other mocking frameworks in that it uses the .Net profiler API to monitor and intercept program execution. This makes it very powerfull, because it is not tied to the same restrictions as other Mock frameworks. Rhino Mocks or similar solutions require that you code to interfaces, and any method you want to mock must be marked as virtual. Some people have even voiced concerns that Typemock is too powerfull, in that is does not force you to design for testability. I think Roy has put that argument to bed with his reply.

In the above example we can use the original SoundEffectDrumRoll implementation, and by setting up the expectation to the Play method Typemock will make sure the method does not actually get executed, and by using the Verify method we make sure the method was in fact called.

Especially when working with legacy code you will find that Typemock offers powerfull features to allow you to test code that would otherwise not be testable without refactoring. On the other hand, if you write new code and use Typemock, you can ignore some of the design issues we’ve talked about here. But that does not mean it’s the right thing to do.


Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

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

Customized Rubric Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: