i am rommel

Starting to write my own history

Dependency Injection to solved unit test problem


   Jan 07

Dependency Injection to solved unit test problem

One of the common problems with unit testing is the dependency of the SUT (systems under test) with other items/modules. So the common approach is to mock/fake this dependency. There are several frameworks that do this mocking, TypeMock, Moq, Rhinomock as some popular ones.

But sometime these dependencies can be done by simple method overload and additional class constructors. Let say for example in our QuickSaas project, we are unit testing the DataComponents and this has a lot of dependencies with the data source (database). Creating sample data and storing it onto the database and retrieving it, is not an option because it does not follow the pattern of unit testing and will just create more headaches (believe me!), so as the solution, Method Overload.

Let say we are retrieving the list of accounts and implement the paging after retrieving. Previously we have a code somewhat below.

 public virtual IList<T> GetEntities(IList<T> entities, ref Pager pager)
 {
            var returnedEntities = this.GetEntities
                               .Skip((pager.PageIndex) * pager.PageSize)
                               .Take(pager.PageSize)
                               .ToList();
            pager.TotalItems = entities.LongCount();
            return returnedEntities;
}

As you can see it is very hard to unit test this because of its dependencies to the output of GetEntities(…), so the solution is below

public virtual IList<T> GetEntities(ref Pager pager)
{
	var returnedEntities = this.GetEntities(this.GetEntities(), ref pager);
	return returnedEntities;
}
 
public virtual IList<T> GetEntities(IList<T> entities, ref Pager pager)
{
	var returnedEntities = entities
		.Skip((pager.PageIndex) * pager.PageSize)
		.Take(pager.PageSize)
		.ToList();
        pager.TotalItems = entities.LongCount();
 
	return returnedEntities;
}

And now we can freely create a unit test like below. Even though we are not really unit testing the GetEntities(ref Pager pager), it much like the same, because the implementation of GetEntities(ref Pager pager) is simply as passing the entities to GetEntities(entities, ref pager), the real core/essence of item to be tested is in GetEntities(entities, ref pager). So I think it’s fine.

[Test]
public void Test_If_Pager_Works_For_Get_Entities()
{
    using (var component = AccountDataComponent.Instance)
    {                             
        //create the reader
        var reader = new DataStub().AccountTable.CreateDataReader();
 
        //load all entities
        var entities = new List<Account>();
        while (reader.Read()) entities.Add(component.LoadEntityFromReader(reader));                        
 
        //do the paging
        var pager = new Pager(1,3 );
        var returnedEntities = component.GetEntities(entities, ref pager);
 
        //assert the values
        Assert.AreEqual(returnedEntities.Count, 1 );
        Assert.AreEqual(pager.PageIndex,1 );
        Assert.AreEqual(pager.PageSize, 3);
        Assert.AreEqual(pager.TotalPages, 2);
        Assert.AreEqual(pager.TotalItems, 4);
    }
}

And more samples…

public virtual IList<T> GetEntities(IList<T> injectedEntities)
{
    if (injectedEntities != null) return injectedEntities;
 
    IList<T> entities = null;
    try
    {
        Connection.Open();
        PrepareGetListCommand();
        using (DbDataReader rdr = Command.ExecuteReader())
        {
            entities = new List<T>();
            while (rdr.Read())
            {
                T entity = LoadEntityFromReader(rdr);
                entities.Add(entity);
            }
        }
    }
    finally
    {
        Connection.Close();
    }
    return entities;
}
 
public override IList<T> GetEntities()
{
    return GetEntities(null);
}

and another sample…

public virtual T GetEntity(int entityId, T injectedEntity)
{
    if (injectedEntity != null) return injectedEntity;
 
 
    T entity = default(T);
    try
    {
        Connection.Open();
        PrepareGetCommand(entityId);
        using (DbDataReader rdr = Command.ExecuteReader())
        {
            while (rdr.Read())
            {
                entity = LoadEntityFromReader(rdr);
            }
        }
    }
    finally
    {
        Connection.Close();
    }
    return entity;
}
 
public override T GetEntity(int entityId)
{
    return GetEntity(entityId, null);
}

Conclusion:

Sometimes the you don’t have to invest a very complicated framework, just a simple design can solved your complicated problem. Just remember the software engineer 101 motto. KISS (Keep it simple stupid) :)

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

blog comments powered by Disqus