Faking IDataReader with ToDataReader()
Have you ever tried to test code that uses an implementation of IDataReader? Perhaps one that uses SqlCommand.ExecuteReader() to return an SqlDataReader. Such code is pretty hard to test because mocking or faking an IDataReader is pretty cumbersome. You’re forced to either mock every successive call to the reader’s Read() and Get*() methods, or you have to set up a DataTable (complete with dummy rows) and call its CreateDataReader() method.
To simplify all this I’ve created a ToDataReader() extension method which operates on IEnumerable<T>. You simply create an array of anonymous types and turn them into an IDataReader. Here’s some sample code to show you what I’m talking about:
var rows = new[] { new { Id = 1, Name = "Foo" }, new { Id = 2, Name = "Bar" } }; using (var rdr = rows.ToDataReader()) { while (rdr.Read()) { Console.WriteLine("{0}\t{1}", rdr.GetInt32(0), rdr.GetString(1)); } }
Pretty cool, huh? Provided you give your anonymous types the same order, property names and data types as the columns you expect your query to return, you can pass the ToDataReader() instance to any method expecting an IDataReader and it’ll return those values.
As an experiment, I’ve thrown the code (as well as a couple of other helpful extension methods on IDataRecord) onto the MSDN Code Gallery. You can reach it here: http://code.msdn.microsoft.com/datareaderext
# Trackback from Twitter Trackbacks for Faking IDataReader with ToDataReader() : Mad Props! - Matt Hamilton [madprops.org] on Topsy.com on 21/11/2009 6:58 AM
# Trackback from Social comments and analytics for this post on 21/11/2009 7:37 AM
Comments
# Peli
1/10/2009 5:45 PM
I'm following the thread from the comment you posted on Phil's blog.
Indeed your ToDataReader looks better than the convoluted Moq semantics.
We've built a stub framework for Pex that lets you do that almost out of the box. Your sample would look like this:
var rows = ...
// SIDataReader is code generated
var current = 0; // row index
var drStub = new SIDataReader() { Read = () => rows[current++] };
IDataReader dr = drStub;
while(dr.Read()) { ...}
# Haacked
21/11/2009 6:58 AM
Slick! Much better than what I did. This'll come in handy for some legacy code I need to work with. :)