Sunday, September 30, 2007

One problem a lot of people face is not being able to test static methods. I am curious as to what other people may be using but this is a technique that I have been using that is fairly effective. I have to point out that I first found this technique in Ayende's Rhino Commons.

To demonstrate this techinque for testing static methods assume we have a class named Assert that has two methods in it IsTrue and Fail. It might look like this:

public sealed class Assert
{
    static public void IsTrue(bool condition, string message)
    {
        if(!condition)
            Fail(message);
    }
 
    static public void Fail(string message)
    {
        throw new AssertionException(message);
    }
}

To test this class we can create an instance class that is a mirror image of the original class without the static keyword:

public sealed class Asserter
{
    public void IsTrue(bool condition, string message)
    {
        if (!condition)
            Fail(message);
    }
 
    public void Fail(string message)
    {
        throw new AssertionException(message);
    }
}

Now we are able to extract an interface from the newly created class:

public interface IAssert
{
    void IsTrue(bool condition, string message);
    void Fail(string message);
}

Next we add a private static getter to the original class that is resolved using Windsor Container and change the static methods to delegate to the private getter.

public sealed class Assert
{
    private static IAssert InternalAssert
    {
        get
        {
            IWindsorContainer container = new WindsorContainer(new XmlInterpreter());
            return container.Resolve<IAssert>();
        }
    }
 
    static public void IsTrue(bool condition, string message)
    {
        InternalAssert.IsTrue(condition, message);
    }
 
    static public void Fail(string message)
    {
        InternalAssert.Fail(message);
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section
            name="castle"
            type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
    </configSections>
    <castle>
        <components>
            <component
                id="assert"
                service="MbUnit.Framework.IAssert, MbUnit.Framework"
                type="MbUnit.Framework.Asserter, MbUnit.Framework" />
        </components>
    </castle>
</configuration>

We can now introduce a class that we can inject a Inversion of Control container into, this allows us to mock out the container at test time:

public class IocContainer
{
    private static IWindsorContainer container;
 
    public IocContainer(IWindsorContainer container)
    {
        IocContainer.container = container;
    }
 
    public static IWindsorContainer Container
    {
        get { return container; }
    }
}

We also need to replace the getter in the static class with our newly created IocContainer class:

private static IAssert InternalAssert
{
    get
    {
        return IocContainer.Container.Resolve<IAssert>();
    }
}

Our test for the static Assert class now looks like this:

[Test]
public void ShouldAssertConditionIsTrue()
{
    MockRepository mockery = new MockRepository();
 
    IWindsorContainer iocContainer = mockery.CreateMock<IWindsorContainer>();
    IocContainer container = new IocContainer(iocContainer);
 
    IAssert assert = mockery.CreateMock<IAssert>();
    using(mockery.Record())
    {
        Expect.Call(IocContainer.Container.Resolve<IAssert>()).Return(assert);
        assert.IsTrue(1 == 2, "One does not equal Two");
    }
    using(mockery.Playback())
    {
        Assert.IsTrue(1==2, "One does not equal Two");
    }
}
Sunday, September 30, 2007 5:42:34 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 

Theme design by Jelle Druyts

Pick a theme: