Mocking the Unmockable: Using Microsoft Moles with Gallio
Posted
by Thomas Weller
on Geeks with Blogs
See other posts from Geeks with Blogs
or by Thomas Weller
Published on Wed, 28 Apr 2010 11:36:39 GMT
Indexed on
2010/04/28
11:53 UTC
Read the original article
Hit count: 647
Usual opensource mocking frameworks (like e.g. Moq or Rhino.Mocks) can mock only interfaces and virtual methods. In contrary to that, Microsoft’s Moles framework can ‘mock’ virtually anything, in that it uses runtime instrumentation to inject callbacks in the method MSIL bodies of the moled methods. Therefore, it is possible to detour any .NET method, including non-virtual/static methods in sealed types. This can be extremely helpful when dealing e.g. with code that calls into the .NET framework, some third-party or legacy stuff etc…
Some useful collected resources (links to website, documentation material and some videos) can be found in my toolbox on Delicious under this link:
http://delicious.com/thomasweller/toolbox+moles
A Gallio extension for Moles
Originally, Moles is a part of Microsoft’s Pex framework and thus integrates best with Visual Studio Unit Tests (MSTest). However, the Moles sample download contains some additional assemblies to also support other unit test frameworks. They provide a Moled attribute to ease the usage of mole types with the respective framework (there are extensions for NUnit, xUnit.net and MbUnit v2 included with the samples). As there is no such extension for the Gallio platform, I did the few required lines myself – the resulting Gallio.Moles.dll is included with the sample download.
With this little assembly in place, it is possible to use Moles with Gallio like that:
[Test, Moled]
public void SomeTest()
{
...
What you can do with it
Moles can be very helpful, if you need to ‘mock’ something other than a virtual or interface-implementing method. This might be the case when dealing with some third-party component, legacy code, or if you want to ‘mock’ the .NET framework itself.
Generally, you need to announce each moled type that you want to use in a test with the MoledType attribute on assembly level. For example:
[assembly: MoledType(typeof(System.IO.File))]
Below are some typical use cases for Moles. For a more detailed overview (incl. naming conventions and an instruction on how to create the required moles assemblies), please refer to the reference material above.
Detouring the .NET framework
Imagine that you want to test a method similar to the one below, which internally calls some framework method:
public void ReadFileContent(string fileName)
{
this.FileContent = System.IO.File.ReadAllText(fileName);
}
Using a mole, you would replace the call to the File.ReadAllText(string) method with a runtime delegate like so:
[Test, Moled]
[Description("This 'mocks' the System.IO.File class with a custom delegate.")]
public void ReadFileContentWithMoles()
{
// arrange ('mock' the FileSystem with a delegate)
System.IO.Moles.MFile.ReadAllTextString =
(fname => fname == FileName ? FileContent : "WrongFileName");
// act
var testTarget = new TestTarget.TestTarget();
testTarget.ReadFileContent(FileName);
// assert
Assert.AreEqual(FileContent, testTarget.FileContent);
}
Detouring static methods and/or classes
A static method like the below…
public static string StaticMethod(int x, int y)
{
return string.Format("{0}{1}", x, y);
}
… can be ‘mocked’ with the following:
[Test, Moled]
public void StaticMethodWithMoles()
{
MStaticClass.StaticMethodInt32Int32 = ((x, y) => "uups");
var result = StaticClass.StaticMethod(1, 2);
Assert.AreEqual("uups", result);
}
Detouring constructors
You can do this delegate thing even with a class’ constructor. The syntax for this is not all too intuitive, because you have to setup the internal state of the mole, but generally it works like a charm. For example, to replace this c’tor…
public class ClassWithCtor
{
public int Value { get; private set; }
public ClassWithCtor(int someValue)
{
this.Value = someValue;
}
}
… you would do the following:
[Test, Moled]
public void ConstructorTestWithMoles()
{
MClassWithCtor.ConstructorInt32 =
((@class, @value) => new MClassWithCtor(@class) {ValueGet = () => 99});
var classWithCtor = new ClassWithCtor(3);
Assert.AreEqual(99, classWithCtor.Value);
}
Detouring abstract base classes
You can also use this approach to ‘mock’ abstract base classes of a class that you call in your test. Assumed that you have something like that:
public abstract class AbstractBaseClass
{
public virtual string SaySomething()
{
return "Hello from base.";
}
}
public class ChildClass : AbstractBaseClass
{
public override string SaySomething()
{
return string.Format(
"Hello from child. Base says: '{0}'",
base.SaySomething());
}
}
Then you would set up the child’s underlying base class like this:
[Test, Moled]
public void AbstractBaseClassTestWithMoles()
{
ChildClass child = new ChildClass();
new MAbstractBaseClass(child)
{
SaySomething = () => "Leave me alone!"
}
.InstanceBehavior = MoleBehaviors.Fallthrough;
var hello = child.SaySomething();
Assert.AreEqual("Hello from child. Base says: 'Leave me alone!'", hello);
}
Setting the moles behavior to a value of MoleBehaviors.Fallthrough causes the ‘original’ method to be called if a respective delegate is not provided explicitly – here it causes the ChildClass’ override of the SaySomething() method to be called.
There are some more possible scenarios, where the Moles framework could be of much help (e.g. it’s also possible to detour interface implementations like IEnumerable<T> and such…). One other possibility that comes to my mind (because I’m currently dealing with that), is to replace calls from repository classes to the ADO.NET Entity Framework O/R mapper with delegates to isolate the repository classes from the underlying database, which otherwise would not be possible…
Usage
Since Moles relies on runtime instrumentation, mole types must be run under the Pex profiler. This only works from inside Visual Studio if you write your tests with MSTest (Visual Studio Unit Test). While other unit test frameworks generally can be used with Moles, they require the respective tests to be run via command line, executed through the moles.runner.exe tool. A typical test execution would be similar to this:
moles.runner.exe <mytests.dll> /runner:<myframework.console.exe> /args:/<myargs>
So, the moled test can be run through tools like NCover or a scripting tool like MSBuild (which makes them easy to run in a Continuous Integration environment), but they are somewhat unhandy to run in the usual TDD workflow (which I described in some detail here). To make this a bit more fluent, I wrote a ReSharper live template to generate the respective command line for the test (it is also included in the sample download – moled_cmd.xml). - This is just a quick-and-dirty ‘solution’. Maybe it makes sense to write an extra Gallio adapter plugin (similar to the many others that are already provided) and include it with the Gallio download package, if there’s sufficient demand for it.
As of now, the only way to run tests with the Moles framework from within Visual Studio is by using them with MSTest. From the command line, anything with a managed console runner can be used (provided that the appropriate extension is in place)…
A typical Gallio/Moles command line (as generated by the mentioned R#-template) looks like that:
"%ProgramFiles%\Microsoft Moles\bin\moles.runner.exe" /runner:"%ProgramFiles%\Gallio\bin\Gallio.Echo.exe" "Gallio.Moles.Demo.dll" /args:/r:IsolatedAppDomain /args:/filter:"ExactType:TestFixture and Member:ReadFileContentWithMoles"
-- Note: When using the command line with Echo (Gallio’s console runner), be sure to always include the IsolatedAppDomain option, otherwise the tests won’t use the instrumentation callbacks! --
License issues
As I already said, the free mocking frameworks can mock only interfaces and virtual methods. if you want to mock other things, you need the Typemock Isolator tool for that, which comes with license costs (Although these ‘costs’ are ridiculously low compared to the value that such a tool can bring to a software project, spending money often is a considerable gateway hurdle in real life...). The Moles framework also is not totally free, but comes with the same license conditions as the (closely related) Pex framework: It is free for academic/non-commercial use only, to use it in a ‘real’ software project requires an MSDN Subscription (from VS2010pro on).
The demo solution
The sample solution (VS 2008) can be downloaded from here. It contains the Gallio.Moles.dll which provides the here described Moled attribute, the above mentioned R#-template (moled_cmd.xml) and a test fixture containing the above described use case scenarios. To run it, you need the Gallio framework (download) and Microsoft Moles (download) being installed in the default locations.
Happy testing…
© Geeks with Blogs or respective owner