Tuesday, October 6, 2009

Using Moq with Spring.NET

Not long into my evaluation of Moq as a mocking framework for our unit testing needs, I had to test a class that used the Spring.NET framework to instantiate a dependant object. Per the rigid definition of a unit test, I wanted to eliminate Spring.NET from the equation. My unit test shouldn't fail because I didn't configure Spring.NET correctly. Besides that, I needed to test the class under different circumstances and couldn't do that without making changes to the configuration file - another TDD no-no.

This part was easy enough by refactoring the method that uses Spring.NET so that I could override it in my test code. I believe I saw this technique referred to as "Inherit and Override". To do this, I simply subclassed the class under test to create a "testable" version with an override for the method that called Spring.NET for the dependant object. In my "testable" class, I return a mock object instead. Nice and simple!

Where things became a bit more complicated is when I wanted to put together a system test for the same functionality. In this case, I do want to use Spring.NET to instantiate the dependant object but still want to mock the object used for testing purposes. Short version is that it handles file I/O which I never want to execute in my tests.

Fortunately, the Moq framework comes with a MockFactory class that can be used in the Spring.NET configuration file to create the mock object we desire for the test. Here is how I setup the configuration file for my test assembly:

<objects xmlns="http://www.springframework.net">
    <object name="MockFactory" type="Moq.MockFactory, Moq">
        <constructor-arg type="Moq.MockBehavior" value="Default" />
    </object>

    <object name="MyObject"
               factory-object="MockFactory"
               factory-method="Create<IMyObject>" />
    </objects>


Now, when running my test, the class calls into the Spring.NET framework for the object which uses the configuration file to call the Create method on the MockFactory class, returning a mock object instead of the concrete class in our application.

There is one catch, however. The object returned from the MockFactory.Create method is of the type Mock<T>. Unless you code your class to accept this type, which would be poor practice, you'll get an InvalidCastException. To work around this, I created my own MockFactory class that delegates to the Moq class but unwraps the returned object so that mocked instance is returned as follows:

internal class MockFactory
{
    private static Moq.MockFactory _moqFactory;

    static MockFactory()
    {
        _moqFactory = new Moq.MockFactory(Moq.MockBehavior.Default);
    }

    public T Create()
        where T : class
    {
        return _moqFactory.Create().Object;
    }
}


I then changed the configuration file to use this class.

<objects xmlns="http://www.springframework.net">
    <object name="MockFactory"
               type="Testing.MockFactory, Testing" />

    <object name="MyObject"
               factory-object="MockFactory"
               factory-method="Create<IMyObject>"/>
</objects>


In the end, getting Moq to play will Spring.NET turned out to be relatively easy. Sure, I had some setup work to do, but now that I've done it once...

2 comments:

  1. Here is an update for the new mock factory class as is has become absolute:


    using Moq;

    namespace MockStuff
    {
    public class MockFactory
    {
    private static MockRepository m_moqRepository;

    public MockFactory()
    {
    m_moqRepository = new MockRepository(MockBehavior.Default);
    }

    public T Create() where T : class
    {
    return m_moqRepository.Create().Object;
    }
    }
    }

    ReplyDelete
  2. You have done fantastic job. Now my problem is that how to write the test cases with object created with spring. in above case MyObject

    ReplyDelete