Justmock is an excellent, fairly new, mocking framework from Telerik that I had the pleasure of getting a free licence for at the launch event. The company I work for has now picked this up and is intending on rolling it out across the development department and I don’t think it can happen soon enough. This is a conversation I have just had (edited and redacted for this blog) with a colleague about using it to mock up the fetching of data.
The current set up was similar to this much more contrived example but it serves to demonstrate the changes we made.
We had a class that depended on the data provider to access the database and return actual values to verify a method was working. For this example, I am using simple number checking but the actual problem was much larger. The data provider fetches a list of numbers based on an initial value and then the checker returns the maximum value in the results set. The data provider interface and checker are below:
public interface IDataProvider
{
List GetNumbers(int start);
}
public class DataProvider : IDataProvider
{
public List GetNumbers(int start)
{
var list = new List();
return list;
}
}
public class NumberChecker
{
public int Getmax()
{
IDataProvider dp = new DataProvider();
return dp.GetNumbers(5).Max();
}
public List GetNumbers()
{
IDataProvider dp = new DataProvider();
return dp.GetNumbers(5);
}
}
This is very simple code and the associated test went something like this:
[TestMethod()]
public void CheckCheckGeneratorReturnsMaximumValue()
{
NumberChecker checker = new NumberChecker();
int expected = checker.GetNumbers().Max();
int actual = checker.Getmax();
Assert.AreEqual(expected, actual);
}
This test passes but it's not very nice. It calls the generator methods twice and then continues to touch the database in order to get the data.
We really wanted to use JustMock so we broke it out and installed it on his machine.
To refactor this code into something testable, we first had to remove that dependency on the data provider. The fact that it has an interface
makes this much easier as we can simply inject an implementer of this interface
into the method and act on that. So without changing the implementation of the data provider and the interface
, the NumberChecker
class became the following:
public class NumberChecker
{
public int Getmax(IDataProvider dp)
{
return dp.GetNumbers(5).Max();
}
public List GetNumbers(IDataProvider dp)
{
return dp.GetNumbers(5);
}
}
Here, we have moved the data provider up to a parameter and are now able to inject any implementer we choose into this method.
This now allows us to test these methods without accessing the data or the real data provider (as we are not testing that here).
JustMock has a method that allows you to return any value when calling a method on a mocked object (Returns
). Using this, we can mock up our data provider to do something that we want it to do rather than access the database. This then allows us to return a custom value so the test now becomes:
[TestMethod()]
public void CheckCheckGeneratorReturnsMaximumValue()
{
var ints = new List { 1, 2, 3, 4, 5 };
var provider = Mock.Create();
Mock.Arrange(() => provider.GetNumbers(Arg.IsAny<int>())).Returns(ints);
NumberChecker checker = new NumberChecker();
int actual = checker.Getmax(provider);
int expected = 5;
Assert.AreEqual(expected, actual);
}
As we can now see, passing in the data provider instance from here makes the test much easier to understand. We have created a new list of integers and are simply returning this from the method on the data provider that we pass in to our NumberChecker
.