Locked History Actions

MyBlog/BlogEntry-2008-03-16

Unit testing a GOF state pattern variant with RhinoMock

Just a day ago I write a small chuck of code which implemented a simple state machine (m/c). Because the m/c is fixed, I implemented it using the classic GOF state pattern. My implementation was a slight variant of that pattern because I did not provide the typical "context class" specified by the pattern. I did this because the state m/c was going to be used in a variety of contexts (in my case ASP.NET web pages). (The context class usually provides methods that the state m/c will call on to implement behavior that needs to occur as part of the events and state transitions.) Instead, following Robert Martin's Interface Segregation Principal, I provided what I call "context interfaces" which were specific to each method representing an event:

public interface SomeEventContext
{
    bool SomeStatus();
    void SomeBehavior();
    // etc...
} 

public class SomeState : StateMachineBase
{
    void SomeEvent(SomeEventContext context)
    { 
        if(!context.SomeStatus())
        {
            context.SomeBahavior();
        // etc...
    }
    // etc...
} 

As I began to write NUnit test for the state m/c I knew that I needed to provide some object which would implement the SMCContext interface. As a first pass I had my unit test class implement the interface. In this particular case the stub implementation of the method did nothing or returned a hard-coded value.

[TestFixture]
public class MyStateMachineUnitTest : SomeEventContext
{
    [Test]
    void SomeTestMethod() { /etc...
    // other test methods etc...

    // my stubs for SomeEventContext
    void SomeEventContext:Behavior1(){}
    bool SomeEventContext:Behavior2() {return true;}

} 

It worked. However for more complex scenarios one might have to take the time to write a stub class just to do unit testing for a class that has a dependency on it. If there are a lot of methods, properties on the interface, you've got a lot of work to do just to test the state m/c. What can one do? How about mock objects!

I've long had interest in mock objects, but have just never gotten around to obtaining a mock object library and learning the API so that I could begin to use it in my unit tests. Recently my buddy RichGrenwick gave me a demo of RhinoMock, a mock object library that he has been using for his unit testing. With this fresh in my mind, I thought of it immediately when I began to write the stub implementation of my state m/c context.

This article is a great introduction to RhinoMocks.

I'm going to follow up blog entry with at least one more to highlight my experience with going back and refactoring my unit tests to use mock objects instead of stubs, so please stay tuned.


CategoryMicrosoftDotNet CategorySoftwareTools CategoryTestDrivenDesign