22 August 2010

Roll your own mocks with RealProxy

These days there are more than enough mocking frameworks to choose from but if you need something a bit different, or just fancy having a go at the problem as an exercise, creating your own is easier than you might think. You don’t need to go anywhere near IL generation for certain tasks as where are a couple of types in the Framework which can get us most of the way on their own.

.NET 4.0 has the DynamicObject class which can be used for this as it allows you to provide custom implementations for any method or property. However there is another class which has been in the Framework since 1.1 that can be used in a similar way.

RealProxy is meant for creating proxy classes for remoting however there’s no reason why we can’t make use of its proxy capabilities and forget the remoting part, instead providing our own mocking implementation. Lets look at a simple example.

If it looks like a duck but can't walk it's a lame duck

If you're using dependency injection and are writing your code defensively you'll probably have constructors which look something like this:

public MyClass(ISupplyConfiguration config, ISupplyDomainInfo domain, ISupplyUserData userRepository)
{
 if(config == null) throw new ArgumentNullException("config");
 if(domain == null) throw new ArgumentNullException("domain");
 if(userRepository == null) throw new ArgumentNullException("userRepository");
 // ...assignments...
}

The unit test for whether this constructor correctly throws ArgumentNullExceptions when it's expected to will require at least some implementation of ISupplyConfiguration and ISupplyDomainInfo in order to successfully test the last check for userRepository.

All we need here is something that looks like the correct interface; it needn't be a concrete implementation or work as, for these tests, all we need is for it to not be null. Here’s how we could achieve this with RealProxy and relatively little code.

First we create a class inheriting from the abstract RealProxy:

public class RubbishProxy : System.Runtime.Remoting.Proxies.RealProxy
{
 public RubbishProxy(Type type) : base(type) {}

 public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
 {
  throw new NotImplementedException();
 }

 /// <summary>
 /// Creates a transparent proxy for type <typeparamref name="T"/> and 
 /// returns it.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <returns></returns>
 public static T Make<T>()
 {
  return (T)new RubbishProxy(typeof(T)).GetTransparentProxy();
 }
}

That's all, effectively just the boiler plate implementation code for the abstract class with one constructor specified and a static generic method for ease of use. We can then use it in our test method like so:

[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ExampleRealWorldTest_EnsureExceptionOnNullConfig()
{
 var myClass = new MyClass(null, null, null);
}

[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ExampleRealWorldTest_EnsureExceptionOnNullDomain()
{
 var config = RubbishProxy.Make<ISupplyConfiguration>();
 var myClass = new MyClass(config, null, null);
}

[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ExampleRealWorldTest_EnsureExceptionOnNullRepository()
{
 var config = RubbishProxy.Make<ISupplyConfiguration>();
 var domain = RubbishProxy.Make<ISupplyDomainInfo>();
 var myClass = new MyClass(config, domain, null);
}

Not bad for one line of code. How about something more complex?

Making a mockery of testing

The Invoke method we overrode in RubbishProxy can perform any action we like including checking arguments, returning values and throwing exceptions. In mocking frameworks, the most common method of setting up this behaviour is using a fluent interface e.g.

[Test]
public void ReadOnlyPropertyReturnsCorrectValue()
{
	var mock = new Mock<IBlah>();
	mock.When(o => o.ReadOnly).Return("thing");
	var blah = mock.Object;
	Assert.AreEqual("thing", blah.ReadOnly);
}

Here the When call captures o.ReadOnly as an expression, determining which member was the invokation target and returning a Call object. The Call object is then used to set up a return value as in the example above, or to check the passed arguments (CheckArguments) or throw an exception (Throw). It can also be set up to ignore the call or, in the case of a method call, to apply any one of those previous behaviours to only when particular arguments are passed in.

[Test]
[ExpectedException(typeof(ForcedException))]
public void MethodCallThrows()
{
	var mock = new Mock<IBlah>();
	mock.When(o => o.GetThing()).Throw();
	var blah = mock.Object;
	int i = blah.GetThing();
}

[Test]
public void MethodCallValid()
{
	var mock = new Mock<IBlah>();
	mock.When(o => o.DoThing(5)).CheckArguments();
	var blah = mock.Object;
	blah.DoThing(5);
}

[Test]
[ExpectedException(typeof(MockException))]
public void MethodCallInvalid()
{
	var mock = new Mock<IBlah>();
	mock.When(o => o.DoThing(5)).CheckArguments();
	var blah = mock.Object;
	blah.DoThing(4);
}

Source code for the example mock framework is up on GitHub here:
http://github.com/dezfowler/LiteMock

No comments: