Subscribe in a reader
Mock ADO.NET with ease using IDataReader Stub objects
Nermin's .Net
My Thoughts on .Net and Software Development

Mock ADO.NET with ease using IDataReader Stub objects

July 10, 2007 11:16 by Admin

Before I start, I would like to point out that if you are confused about differences between Mock and Stub objects, please read the Fowler’s post on the subject:

http://www.martinfowler.com/articles/mocksArentStubs.html

I have seen too many “Unit tests” where developers do not isolate the test to the unit (object/method) being tested.  Yes they are testing a business object, but to test its behavior they load half of the object hierarchy in the project.  Moreover if your object gets initialized from external resource like a database, then they create this complex “test databases” that contain their test data.  These databases have to be shared with other developers.  If you have a continuous build environment that runs tests as a part of the build process, then you have to have a copy of the test database there.  All these test databases have to be modified as you modify schema/data in your development database.  In addition if your test modifies data in the database then you need to setup an additional process in the SetUp or Teardown to restore the data to initial state.

So the test should be simpler if we mock the db dependency, right?  So what does that involve?  Let’s say we have an object called project Project with constructor as described below:

public Project(IProjectGateway gateway, int id)

{

    using(IDataReader dr = gateway.GetProjectBy(id)) {

        if(dr.Read()) {

            _id = dr.GetInt32(0);

            _name = dr.GetString(1);

            _date = dr.GetDateTime(2);                   

        }

    }

}

 

Where IProjectGateway is an interface defining a set of methods/and object in charge of persistence of the Project data to and from the database.    So lets look how that interface might look like:

public interface IProjectGateway {

    IDataReader GetProjectBy(int id);

    ...

}

So far this is simple, right? Actual implementation of that interface does not matter for our test.  Why?  Because we are not testing database, its resources/file storage, hardware, connection pooling, network connections, etc.  All we are supposed to test is that our object properly populates its field from a returned DataReader.  

To test the Project object without the database roundtrip we will only need to mock the IProjectGateway, setting the expectations for the GetProjectBy(id) to return our test data (data reader).  I have to mention that the dynamic mocks in the examples bellow were done using my favorite mocking tool TypeMock.Net.

[Test]

public void AssureFetchMapsFields()

{

    Mock<IProjectGateway> projGatewayMock = MockManager.Mock<IProjectGateway>();

 

    projGatewayMock.ExpectAndReturn("GetProjectBy", new ProjectDataStub().CreateDataReader());

   

    Project project = new Project(projGatewayMock.MockedInstance,1);

 

    Assert.AreEqual(1,project.Id);

    Assert.AreEqual("Test",project.Name);

    Assert.AreEqual(DateTime.Parse("1/1/2000"),project.Date);

}

 

So lets see what exactly have we done in the test above.  First line creates our dynamic mock instance.  Second line is the interesting part.  It states that we expect one method call on our IProjectGatewayMock, and that is “GetProjectBy()” method.  Once it is called we want the IDataReader to be returned from ProjectDataStub.CreateDataReader().  The rest of the code instantiates the Project object and then assures that the Project’s properties are initialized.

But what about this ProjectDataStub.CreateDataReader()?  Well I have noticed the ability of the DataTable objects to create an instance of TableDataReader(which implements IDataReader).  So theoretically we could create a DataTable with column types that reflect the types of the actual columns of the table/view we are fetching from db and populate this DataTable with test record(s).  Then our mock IProjectGateway can return the IDataReader from this object, and voila – no db or any other external connection used in the test.

So if we follow this logic the ProjectDataStub should be an object that inherits from DataTable and populates its columns and rows with test records when it is constructed.  But coding these stub object for each and every test might be a bit tedious.  To solve this problem I have created a rather simple tool that allows us to generate this DataStub simply by copying and pasting select SQL statements from the fetch Stored Procedure and executing it.

Above is the scren shot showing how tool works and its output.  If you think that this tool might be useful for you feel free to download the code from the link bellow:

StubGenerator.zip (780.62 KB)

Is this all when it comes to testing the DAL?  No, obviously we have only tested the data mapping part.  Code in this Project constructor can throw SqlExcpetion (database down, network problem, schema problem).  We need to assure that our code handles that.

Now putting the try/ctach block in the Project constructor does not make sense - I do not want Project instantiated if we were unable to retreive its data.  So how do we test this case?  Lets assume that our application is using Model View Presenter architecture, and that the object instantiating our Project is the Presenter object of the View that displays Project.  Obviously we need to assure that this Presenter can recover from the SqlException thrown by Project.  Lets take a look at the code bellow:

public class ProjectPresenter

{

....

public void DisplayProject(){

    try{

        Project p = new Project();

 

        ... do something with project like display it on the view etc...

 

    }catch(SqlException e){

        Log.LoqException(e);       

    }

}

So if we can assure that the Log.LogException(e) is called when the Project throws the SqlException, that would be a proof that the exception was handled.  Keep in mind that in Test Driven Development we would be writting the test prior to the DisplayProject() method being written (and the catch block inside of it existing)

Dynamic mocking helps us here also.  In this case we are testing the Presenter, which means that the other two objects Log and Project would be mocked.  Test would encompass mocking ProjectConstructor instead of returning Project throws SqlException, and then assuring that the Log Mock accepts the call to LogException(e).

In addition there would be tests that we need to run for Insert, Update and Delete (if Project needs to support that), but I will leave that for a future post.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: C# | Mock | TDD | Unit Testing
Actions: E-mail | Permalink | Comments (3) | Comment RSSRSS comment feed

Related posts

Comments

July 30. 2007 11:41

 Mike

Any chance of including the dependent assemblys for the StubGenerator, Rhino.Mocks etc so we don't have to hunt them down or like me just give up as it's not worth the hassle.

Mike

October 1. 2007 00:48

Nermin Dibek

Mike,

Actually Rhino.Mocks, and Enterprise Library blocks are not needed - I have removed those from the solution, and posted a new file that can be downloaded from that link. For the purpose of this example I decided to go with another dynamic mocking library called TypeMock, and make an example more generic by not using Data Access Block from enterprise library. Now the only 3rd party references needed in this solution is TypeMock. Unfortunately TypeMock runs on top of profiler API (and your tests need to attach to that process), therefore you need a full blown install for the TypeMock.net - I can not provide only the assembly, it will not work.

Nermin Dibek

February 7. 2008 06:51

trackback

Trackback from Nermin Dibek

Fluent Stubs

Nermin Dibek

Add comment


(Will show your Gravatar icon)  

  Country flag





Live preview

August 28. 2008 10:54