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 /t>()
where T : class
{
return _moqFactory.Create /t>().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...
Here is an update for the new mock factory class as is has become absolute:
ReplyDeleteusing 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;
}
}
}
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