I have a Data Access Layer in my application which wraps an ADO.NET data provider. The DAL converts the data returned by the data provider into .NET objects. I've seen a lot of posts advising against unit testing the DAL, but it worries me that so much could go wrong in there - there's lots of looping and casting and null checks.
I had some thoughts about creating a mock DbProvider with something like RhinoMocks, but the number of interfaces I'd have to mock out in each test would be overwhelming, and the number of expectations I'd have to set would make the tests very hard to read. It seems that each test would be more complex than the code it was testing - which would be a disaster from the perspective of the 3 goals of unit testing:
- Readability
- Maintainability
- Trustworthiness
I had an idea to implement a friendly DbProviderFactory to load the sample data from xml. I could plug it in via Dependency Injection in the tests. It should make maintaining the tests much simpler. A trivial example might be:
[TestCase]
public void CanGetCustomer()
{
var expectedCommand = new XmlCommand("sp_get_customer");
expectedCommand.ExpectExecuteDataReader(
resultSet: @"<customer firstName=""Joe"" lastName=""Blogs"" ... />");
var factory = new XmlProviderFactory(expectedCommand);
var dal = new CustomerDal(factory);
Customer customer = dal.GetCustomer();
Assert.IsNotNull(customer, "The customer should never be null");
Assert.AreEqual(
"Joe", customer.FirstName,
"The customer had an unexpected FirstName.");
}
I think this approach - using a friendly DbProvider - might make it easier to test the DAL code. It would have the following advantages:
- The test data would be in xml, and could be placed in source control along with the unit tests. It could be in external files, or in-line in the tests.
- I'm not using a real database so this eliminates the statefulness problem. So I don't have to put a database into a known state prior to each test.
- I don't have to mock out all of the ADO.NET interfaces in each test. I'll code one set of fake implementations which I can re-use all over the codebase.
Could people provide some critique on this idea? Is there already a similar implementation that I could use for this?
Thanks