Using Mock Objects When Testing LINQ Code
I was wondering the other day whether LINQ could be used with NMock easily. One problem with testing code that has not been written to work with unit tests is that if you test business logic, you often end up making multiple round-trips to the database for each test run. With a very large test suite that can turn a few minute’s work into hours for a test suite. the best approach to this is to use mock data access components to dispense canned results, rather than going all the way through to the database.
After a little thought it became clear that all you have to do is override the **_IOrderedQueryable
I’m a great believer in the medicinal uses of mock objects. Making your classes testable using mocking enforces a level of encapsulation that adds good structure to your code. I find that the end results are often much cleaner if you design your systems with mocking in mind.
Lets start with a class that you were querying over in your code. This is the type that you are expecting to get back from your query.
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">MyEntity
</span>{
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">string</span> Name
{
<span style="color:rgb(0,0,255);">get</span> { <span style="color:rgb(0,0,255);">return</span> name; }
<span style="color:rgb(0,0,255);">set</span> { name = <span style="color:rgb(0,0,255);">value</span>; }
}
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">int</span> Age
{
<span style="color:rgb(0,0,255);">get</span> { <span style="color:rgb(0,0,255);">return</span> age; }
<span style="color:rgb(0,0,255);">set</span> { age = <span style="color:rgb(0,0,255);">value</span>; }
}
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">string</span> Desc
{
<span style="color:rgb(0,0,255);">get</span> { <span style="color:rgb(0,0,255);">return</span> desc; }
<span style="color:rgb(0,0,255);">set</span> { desc = <span style="color:rgb(0,0,255);">value</span>; }
}
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(0,0,255);">string</span> name;
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(0,0,255);">int</span> age;
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(0,0,255);">string</span> desc;
}
Now you need to create a new context object derived from the DLINQ DataContext class, but providing a new constructor function. You can create other ways to insert the data you want your query to return, but the constructor is all that is necessary for this simple example.
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">MockContext</span> : <span style="color:rgb(43,145,175);">DataContext
</span>{
<span style="color:rgb(0,0,255);"> #region</span> constructors
<span style="color:rgb(0,0,255);">public</span> MockContext(<span style="color:rgb(43,145,175);">IEnumerable</span> col):<span style="color:rgb(0,0,255);">base</span>(<span style="color:rgb(163,21,21);">""</span>)
{
User = <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">MockQuery</span><<span style="color:rgb(43,145,175);">MyEntity</span>>(col);
}
<font color="#008000">// other constructors removed for readability</font>
<span style="color:rgb(0,0,255);"> #endregion
</span> <span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(43,145,175);">MockQuery</span><<span style="color:rgb(43,145,175);">MyEntity</span>> User;
}
Note that you are passing in an untyped IEnumerable rather than an **_IEnumerable
var q = from u <span style="color:rgb(0,0,255);">in</span> db.User
where u.Name.Contains(<span style="color:rgb(163,21,21);">"Andrew"</span>) && u.Age < 40
select <span style="color:rgb(0,0,255);">new</span> {u.Age};
The result of db.User is an **_IOrderedQueryable
The query object also has a constructor that takes an IEnumerable, and it keeps that till GetEnumerator() gets called later on. CreateQuery and CloneQueryForNewType just pass the IEnumerable _**around till the time is right. **_GetEnumerator just iterates the collection in the cannedResponse iterator casting them to the return type expected for the resulting query.
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">MockQuery</span><T> : <span style="color:rgb(43,145,175);">IOrderedQueryable</span><T>
{
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(0,0,255);">readonly</span> <span style="color:rgb(43,145,175);">IEnumerable</span> cannedResponse;
<span style="color:rgb(0,0,255);">public</span> MockQuery(<span style="color:rgb(43,145,175);">IEnumerable</span> cannedResponse)
{
<span style="color:rgb(0,0,255);">this</span>.cannedResponse = cannedResponse;
}
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(43,145,175);">Expression</span> expression;
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(43,145,175);">Type</span> elementType;
<span style="color:rgb(0,0,255);"> #region</span> IQueryable<T> Members
<span style="color:rgb(43,145,175);">IQueryable</span><S> <span style="color:rgb(43,145,175);">IQueryable</span><T>.CreateQuery<S>(<span style="color:rgb(43,145,175);">Expression</span> expression)
{
<span style="color:rgb(43,145,175);">MockQuery</span><S> newQuery = CloneQueryForNewType<S>();
newQuery.expression = expression;
<span style="color:rgb(0,0,255);">return</span> newQuery;
}
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(43,145,175);">MockQuery</span><S> CloneQueryForNewType<S>()
{
<span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">MockQuery</span><S>(cannedResponse);
}
<span style="color:rgb(0,0,255);"> #endregion
#region</span> IEnumerable<T> Members
<span style="color:rgb(43,145,175);">IEnumerator</span><T> <span style="color:rgb(43,145,175);">IEnumerable</span><T>.GetEnumerator()
{
<span style="color:rgb(0,0,255);">foreach</span> (T t <span style="color:rgb(0,0,255);">in</span> cannedResponse)
{
<span style="color:rgb(0,0,255);">yield</span> <span style="color:rgb(0,0,255);">return</span> t;
}
}
<span style="color:rgb(0,0,255);"> #endregion
</span><span style="color:rgb(0,0,255);">
#region</span> IQueryable Members
<span style="color:rgb(43,145,175);">Expression</span> <span style="color:rgb(43,145,175);">IQueryable</span>.Expression
{
<span style="color:rgb(0,0,255);">get</span> { <span style="color:rgb(0,0,255);">return</span> System.Expressions.<span style="color:rgb(43,145,175);">Expression</span>.Constant(<span style="color:rgb(0,0,255);">this</span>); }
}
<span style="color:rgb(43,145,175);">Type</span> <span style="color:rgb(43,145,175);">IQueryable</span>.ElementType
{
<span style="color:rgb(0,0,255);">get</span> { <span style="color:rgb(0,0,255);">return</span> elementType; }
}
<span style="color:rgb(0,0,255);"> #endregion
</span>}
For the sake of readability I have left out the required interface methods that were not implemented, since they play no part in this solution. Now lets look at a little test harness:
<span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">Program
</span>{
<span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">void</span> Main(<span style="color:rgb(0,0,255);">string</span>[] args)
{
<span style="color:rgb(43,145,175);">MockContext</span> db = <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">MockContext</span>(GetMockResults());
var q = from u <span style="color:rgb(0,0,255);">in</span> db.User
where u.Name.Contains(<span style="color:rgb(163,21,21);">"Andrew"</span>) && u.Age < 40
select u;
<span style="color:rgb(0,0,255);">foreach</span> (<span style="color:rgb(43,145,175);">MyEntity</span> u <span style="color:rgb(0,0,255);">in</span> q)
{
<span style="color:rgb(43,145,175);">Debug</span>.WriteLine(<span style="color:rgb(0,0,255);">string</span>.Format(<span style="color:rgb(163,21,21);">"entity {0}, {1}, {2}"</span>, u.Name, u.Age, u.Desc));
}
}
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(43,145,175);">IEnumerable</span> GetMockResults()
{
<span style="color:rgb(0,0,255);">for</span> (<span style="color:rgb(0,0,255);">int</span> i = 0; i < 20; i++)
{
<span style="color:rgb(43,145,175);">MyEntity</span> r = <span style="color:rgb(0,0,255);">new</span> <span style="color:rgb(43,145,175);">MyEntity</span>();
r.Name = <span style="color:rgb(163,21,21);">"name "</span> + i;
r.Age = 30 + i;
r.Desc = <span style="color:rgb(163,21,21);">"desc "</span> + i;
<span style="color:rgb(0,0,255);">yield</span> <span style="color:rgb(0,0,255);">return</span> r;
}
}
}
The only intrusion here is the explicit use of MockContext. In the production code that is to be tested, you can’t just go inserting MockContext where you would have used the SqlMetal generated context. You need to use a class factory that will allow you to provide the MockContext on demand in a unit test, but dispense a true LINQ to SQL context when in production. That way, all client code will just use mock data without knowing it.
Here’s the pattern that I generally follow. I got it from the Java community, but I can’t remember where:
<span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">DbContextClassFactory
</span>{
<span style="color:rgb(0,0,255);">class</span> <span style="color:rgb(43,145,175);">Environment
</span> {
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">bool</span> inUnitTest = <span style="color:rgb(0,0,255);">false</span>;
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(0,0,255);">bool</span> InUnitTest
{
<span style="color:rgb(0,0,255);">get</span> { <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(43,145,175);">Environment</span>.inUnitTest; }
<span style="color:rgb(0,0,255);">set</span> { <span style="color:rgb(43,145,175);">Environment</span>.inUnitTest = <span style="color:rgb(0,0,255);">value</span>; }
}
<span style="color:rgb(0,0,255);">private</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(43,145,175);">DataContext</span> objectToDispense = <span style="color:rgb(0,0,255);">null</span>;
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">static</span> <span style="color:rgb(43,145,175);">DataContext</span> ObjectToDispense
{
<span style="color:rgb(0,0,255);">get</span> { <span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(43,145,175);">Environment</span>.objectToDispense; }
<span style="color:rgb(0,0,255);">set</span> { <span style="color:rgb(43,145,175);">Environment</span>.objectToDispense = <span style="color:rgb(0,0,255);">value</span>; }
}
}
<span style="color:rgb(0,0,255);">public</span> <span style="color:rgb(0,0,255);">object</span> GetDB()
{
<span style="color:rgb(0,0,255);">if</span> (<span style="color:rgb(43,145,175);">Environment</span>.InUnitTest)
<span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(43,145,175);">Environment</span>.ObjectToDispense;
<span style="color:rgb(0,0,255);">return</span> <span style="color:rgb(0,0,255);">new</span> TheRealContext() <span style="color:rgb(0,0,255);">as</span> <span style="color:rgb(43,145,175);">DataContext</span>;
}
}
Now you can create your query like this:
DbContextClassFactory.Environment.ObjectToDispense = <span style="color:rgb(0,0,255);">new</span> MockContext(GetMockResults());
var q = from u <span style="color:rgb(0,0,255);">in</span> DbContextClassFactory.GetDB() where ...
And your client code will use the MockContext if there is one, otherwise it will use a LINQ to SQL context to talk to the real database. Perhaps we should call this Mockeries rather than Mock Queries. What do you think?
Andrew Matthews
C# LINQ programming