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");
}
}