AKA ‘replace any static method call with a lamda allowing you to test first’

I’m, like many others, a strong believer of TDD, DRY, Build Only Business and Do The Simplest Thing That Could Possibly Work. However sometimes they don’t seem to co-exist very nicely. Although I’m a pretty good at starting holy-crusades against developers in my team that don’t do Test First they always had this one thing I would give them right: there is no use in creating this kind of code:

   1: public interface IClock

   2: {

   3:     DateTime Now { get; }

   4: }

   5:  

   6: public class MyCoolService

   7: {

   8:     private IClock _clock;

   9:     public MyCoolService(IClock clock)

  10:     {

  11:         if (clock == null) throw new ArgumentNullException("clock");

  12:         _clock = clock;

  13:     }

  14:  

  15:     public void Do()

  16:     {

  17:         if (_clock.Now.Date == new DateTime(2001, 1, 1).Date)

  18:             RegisterNewYear();

  19:         ....

  20:     }

  21: }

This kind of code is needed for stubbing and mocking frameworks like RhinoMock, Moq, EasyMock.NET, … and allow you to isolate your subject under test. Very nice, but you cannot expect your co-developers to wrap every static method call or third party funky API. .NET is full of stuff like HttpContext.Current, Cache, DateTime, System.IO.XXX …

Wrapping these stuff goes directly against the DRY and DTSTTCPW principles and delivers no business value whatsoever to your customer.

Things got even worse as soon as Functional Programming started replacing my traditional strict OO way of thinking, passing around delegates and using the static methods available inside the framework eliminates most Unit Testing frameworks… Let’s see how hard it would be to unit-test this kind of code:

   1: public static class FileParsingRuntime

   2: {

   3:     public static void DeleteProcessedFiles(IEnumerable<string> directories)

   4:     {

   5:         directories

   6:             .Where(Directory.Exists)

   7:             .Select(Directory.GetFiles)

   8:             .Expand() // Expands x number of IEnumerable<T>: {a[1,2]},{b[3,4,5]},.. => c[1..5]

   9:             .Where(x => x.Contains("processed"))

  10:             .Do(File.Delete);

  11:     }

  12: }

There are no wrappers here around the System.IO.Directory static method invocations here, the only way to fully test this code before writing it would force me to create some kind of ‘temporary’ ‘virtual’ file system and use those directories to test this method or write a full-blown scenario test.

Luckily for me, MS Research is working hard on some unit test tooling called Pex. Pex consist of several tools but the one I needed to write the test before I could write the code above is called “Moles”.

Moles allows you to replace any static method with a custom lambda substitute. To do that you first need to download Pex and install it, next you have to add a .moles file to your unit test project in which you describe the assemblies you want your moles to dig in:

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <Moles xmlns="http://schemas.microsoft.com/moles/2010/">

   3:   <Assembly Name="mscorlib" />

   4: </Moles>

I needed to replace some behavior of System.IO classes so I added the mscorlib in which they reside. Pex generates a wrapper assembly (smells like Interop) and exposes every class and method inside it after prefixing it with M, marking it as a mole.

blogpost moles

Now it’s time to reveal the actual unit test:

   1: [TestMethod]

   2: [HostType("Moles")]

   3: public void Test_Deletion_Of_Files_Works()

   4: {

   5:     // Creating a virtual file system:

   6:     var directories = new List<string>() { @"c:\temp\olapola\", @"c:\temp\olaFabiola\", @"c:\doesnotexists" };

   7:     var files = new Dictionary<string, string[]>();

   8:     files.Add(directories[0], new string[] { directories[0] + "File1processed.txt", directories[0] + "File2.txt" });

   9:     files.Add(directories[1], new string[] { directories[1] + "File3processed.txt" });

  10:     var deletedFiles = new List<string>();

  11:     // Replace the .NET API calls to interact with my virtual file system:

  12:     MDirectory.ExistsString = (n) => n != directories[ 2 ];

  13:     MDirectory.GetFilesString = (n) =>  files[ n ];

  14:     MFile.DeleteString = (n) => deletedFiles.Add(n);

  15:     // Execute

  16:     FileParsingRuntime.DeleteProcessedFiles(directories);

  17:     // Assert

  18:     Assert.AreEqual(2, deletedFiles.Count);

  19:     Assert.IsTrue(deletedFiles.Contains(@"c:\temp\olapola\File1processed.txt"));

  20:     Assert.IsTrue(deletedFiles.Contains(@"c:\temp\olaFabiola\File3processed.txt"));

  21: }

Notice that the following method calls are replaced using lambda expressions:

Also notice that the required HostTypeAttribute also plays nicely with NUnit, MBUnit, XUnit…

Let’s now hope that Pex can soon ship together with the VS Quality Tools stack!

3 thoughts on “Stubs & Mocks meet their new friends: the Moles

  1. Looks pretty cool!

    BTW, what is that Expand() extension method you are using? Looks quite a lot like the Out of the Box SelectMany() to me!

  2. Hi Frank,

    yeah, it also filters non default values, so it’s like:

    public static IEnumerable Expand(this IEnumerable> items)
    {
    foreach(var x in items.Where(z => z != default(T))
    foreach(var y in x.Where(z => z != default(T))
    yield return y;
    }

    it would probably better name it: SelectManyExceptDefault or something like that :) it comes from my own set of core functions that I always reuse and I should let it review sometime I gues :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>