31 May 2011

Moles requires tests to be IN an instrumented process

After adopting Moles as my dependency isolation utility of choice for .NET projects, I began to encounter an exception that could not be explained by anyone, including Peli:
Moles requires tests to be IN an instrumented process.

To compound my frustration, my unit tests involving "moled" types began to work sometimes, and would work other times.  To add frustration, no code changes took place between the successful and unsuccessful test executions.

But something had indeed changed.  Not in the code.  Not on my workstation. Not in Visual Studio 2010 or Team Foundation Server.  How I executed the text changed.

I have DevExpress Tools for Visual Studio installed on my workstation and VS2010.  This add-in suite includes the Unit Test Runner tool.  This neat utility inserts a convenient test execution icon next to every test namespace, class, and method declaration.  Simply click the icon, and select Run Test or Debug Test, and you're on your way.  However, DevExpress is not aware of compiler commands and switches required for Moles compatibility.

The Visual Studio 2010 testing tools are modified by the Moles installer, to include the commands and switches required to implement the Moles framework.  Tests executed directly through Visual Studio's interfaces work fine.  Moles also includes integration with other popular testing harnesses, too.
The following target class and test class will throw the exception, when executed through DevExpress, but will pass when executed through Visual Studio.

TARGET CLASS:
using System.IO;
 
namespace InstanceMoleDemo
{
    public class Class1
    {
        public Class1(IMySettings settings)
        {
            if (!settings.DirectoryInfo1.Exists)
                settings.DirectoryInfo1.Create();
 
            if (!settings.DirectoryInfo2.Exists)
                settings.DirectoryInfo2.Create();
 
            if (!settings.DirectoryInfo3.Exists)
                settings.DirectoryInfo3.Create();
        }
    }
 
    public interface IMySettings
    {
        DirectoryInfo DirectoryInfo1 { get; }
        DirectoryInfo DirectoryInfo2 { get; }
        DirectoryInfo DirectoryInfo3 { get; }
    }
 
    public class MySettings : IMySettings
    {
        public MySettings(string directoryPath1, string directoryPath2, string directoryPath3)
        {
            _directoryInfo1 = new DirectoryInfo(directoryPath1);
            _directoryInfo2 = new DirectoryInfo(directoryPath2);
            _directoryInfo3 = new DirectoryInfo(directoryPath3);
        }
 
        private DirectoryInfo _directoryInfo1;
        public DirectoryInfo DirectoryInfo1
        {
            get { return _directoryInfo1; }
        }
 
        private DirectoryInfo _directoryInfo2;
        public DirectoryInfo DirectoryInfo2
        {
            get { return _directoryInfo2; }
        }
 
        private DirectoryInfo _directoryInfo3;
        public DirectoryInfo DirectoryInfo3
        {
            get { return _directoryInfo3; }
        }
    }
}

TEST CLASS:
using System.IO;
using System.IO.Moles;
using InstanceMoleDemo;
using Microsoft.Moles.Framework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[assemblyMoledType(typeof(System.IO.DirectoryInfo))]
 
namespace TestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        [HostType("Moles")]
        public void Class1ConstructorTestsDirectory1()
        {
            // Arrange.
            var result = false;
 
            MDirectoryInfo.AllInstances.ExistsGet = dirInfo => true;
            MDirectoryInfo.AllInstances.Create = dirInfo => {};
 
            var settings = new TestMySettings()
            {
                DirectoryInfo1 = new DirectoryInfo("S:\\BogusDirectory"),
                DirectoryInfo2 = new DirectoryInfo("S:\\BogusDirectory"),
                DirectoryInfo3 = new DirectoryInfo("S:\\BogusDirectory")
            };
 
            // Mole the settings.DirectoryInfo3 instance.
            var moledD3 = new MDirectoryInfo(settings.DirectoryInfo3);
            moledD3.ExistsGet = () =>
            {
                result = true;
                return false;
            };
 
            // Act.
            var c = new Class1(settings);
 
            // Assert.
            Assert.IsTrue(result);
        }
    }
 
    public class TestMySettings : IMySettings
    {
        public DirectoryInfo DirectoryInfo1 { getset; }
        public DirectoryInfo DirectoryInfo2 { getset; }
        public DirectoryInfo DirectoryInfo3 { getset; }
    }
}


No comments:

Post a Comment

Please provide details, when posting technical comments. If you find an error in sample code or have found bad information/misinformation in a post, please e-mail me details, so I can make corrections as quickly as possible.