Unit Test a DataReader with NUnit, Moq and Stubs

This post will allow you to unit test objects that have a dependency on a SqlDataReader by mocking/stubbing a data reader.

Here I've made a 'wrapper' of sorts for the good ol' Microsoft SqlHelper class, which is ancient now, ya? Since the SqlHelper.ExecuteReader's method class implements the IDataReader interface we're in luck.

public interface IFetch {
//add members as necessary
IDataReader ExecuteDataReader(string connectionString, 
string storedProcedureName,SqlParameter[] parameters);
}
 
public class Fetch : IFetch {
 
public IDataReader ExecuteDataReader(string connectionString, 
string storedProcedureName, SqlParameter[] parameters){
return SqlHelper.ExecuteReader(connectionString, 
CommandType.StoredProcedure,storedProcedureName, 
parameters);
}
 
}

Next we create our object from the results of our IDataReader. The SqlHelper class removes the worry about mocking SqlCommand and SqlConnection classes. All you need to worry about are the results (SqlDataReader).

(You can make your own RockStar object, fo sho.)

Whether you call it constructor initialization or constructor chaining, we have it here, and will allow us to inject the correct dependency, in this case, an interface that defines an ExecuteReader method. (I've never gotten into DI/IoC frameworks, should I, and which??)

private readonly RockStar rs;
private readonly IFetch fetch;
 
//here's the magic sauce for the unittests
public FetchCms(IFetch fetch, RockStar rs){
this.fetch = fetch;
this.rs = rs;
}
//production code calls this which calls 
//the other constructor. mmm.
public FetchRockStar() : this(new Fetch(), new RockStar()) { }
 
public RockStar GetRockStar(string urlToLookup){
try
{
var parms = new[] { new SqlParameter("@urlName", urlToLookup) };
using (IDataReader reader = 
fetch.ExecuteDataReader("localhell", "rockstar_page_get",parms)){
if (reader != null && reader.Read()){
rs.Name = reader["name"].ToString();
rs.Guitar = reader["guitar"].ToString();
//add some logic... and so on...                       
}
}
}
catch //swine flu
{}
return fs;
}

ok, so now your production code is hawt, but how do you 'fake' a reader, or 'fake' its results? Good question, but never fear, Phil Haack has you covered with his totally rock-tacular StubDataReader class. Get it.

so now, in your UnitTest project...

I'm creating some fake results that I can use to test my expectations, using the StubDataReader class you've downloaded above and added to your UnitTest project.

private static StubDataReader getData_Kerry_King(){
var resultSet = new StubResultSet("name", "guitar");
resultSet.AddRow("Kerry King", "B.C. Rich");
return new StubDataReader(resultSet);
}

I'm using the Moq framework to mock my interfaces. (it's from an older release, hence the Expect calls rather than the Setup calls [anyone: what does the new version get me?])

[Test]
public void Execute_DataReader_Test() {
var m = new Mock<IFetch>();
//here i'm expecting that my ExecuteReader implementation
//return my 'fake' data
m.Expect(
x => x.ExecuteReader(
It.IsAny<string>(), 
It.IsAny<string>(), 
It.IsAny<SqlParameter[]>()
)
).Returns(getData_Kerry_King());
 
var rockStar = new RockStar();
// pass IN the interface using the special constructor.
var fetch = new FetchRockStar(m.Object, rockStar);
rockStar = fetch.GetRockStar("kerry-king");
//assert
Assert.AreEqual("Kerry King",rockStar.Name);
Assert.AreEqual("B.C. Rich",rockStar.Guitar);
}
 

Even Kerry thinks you should be testing!



kick it on DotNetKicks.com

About Brian


profile for bluevoodoo1 on Stack Exchange, a network of free, community-driven Q&A sites

Brian Canzanella brings you nifty tips and tricks for most things .NET. read more...

Readers / Stuff