1

Possible Duplicate:
Writing “unit testable” code?

I am new to unit testing. Today on SO I found an answer to a question about interfaces in c#. That got me thinking about best practices for building an applications that's testable by design.

I use interfaces very lightly in the main application that I work on. That's made it very difficult to test because I have no way of injecting test data into most classes as each class relies directly upon other classes, and thus the other classes implementations.

So my question is, for a C# application, how would you design your classes and implementations, and what tools would you use to ensure that methods and classes can be independently unit tested by supplying test data for each method or class.

EDIT: Specifically, if you look at the question I linked to, the answer uses this: IWidget w = ObjectFactory.GetInstance();

I never used a class/object factory, so I'm curious how that works and how it would be implemented.

Community
  • 1
  • 1
Chris Thompson
  • 16,203
  • 9
  • 45
  • 62
  • Chris, this question was asked recently: http://stackoverflow.com/questions/1007458/writing-unit-testable-code. This was easy to find, just searching for "unit test". – John Saunders Jun 23 '09 at 23:34
  • Thanks. I did a quick search but all the results I saw were about specific unit tests. Sorry for the duplicate. – Chris Thompson Jun 23 '09 at 23:36

3 Answers3

4

Dependency Injection is the solution you are looking for. The general problem has to do with where your dependencies are created. Normally, when writing an object-oriented program, the natural instinct is to create your dependencies directly using the new keyword at the location you need your dependencies. Sometimes you may create long-lived dependencies in a constructor.

To make your classes more unit testable, you need to "invert" that norm, and create your dependencies externally (or create a factory/provider/context that can in turn be injected and used to create instances of other dependencies), and "inject" those dependencies into your class. The two most common mechanisms of injection are either as parameters to a constructor, or with properties with setters. By externalizing dependency management in this way, you are easily able to create mocked versions of those dependencies and pass those in, allowing you to test your units of code in full isolation from the rest of your application.

To support dependency injection and make it easier to manage Inversion of Control (IoC) containers have appeared. An IoC container is a framework that allows you to configure dependency graphs independently of the classes that participate in in those graphs. Once a dependency graph is configured (usually rooted at the single key class of interest), you can easily create instances of your objects at runtime without having to worry about manually creating all of the required dependencies as well. This helps in creating very loosely coupled, flexible code that is easy to reconfigure. An example of a very good IoC container is Castle Windsor, which provides a very rich framework for wiring up classes via dependency injection.

A very simple example of Dependency Injection would be something like the following:

interface ITaskService
{
    void SomeOperation();
}

interface IEntityService
{
    Entity GetEntity(object key);
    Entity Save(Entity entity);
}

class TaskService: ITaskService
{
    public TaskService(EntityServiceFactory factory)
    {
        m_factory = factory;
    }

    private EntityServiceFactory m_factory; // Dependency

    public void SomeOperation() // Method must be concurrent, so create new IEntityService each call
    {
        IEntityService entitySvc = m_factory.GetEntityService();
        Entity entity = entitySvc.GetEntity(...);
        // Do some work with entity
        entitySvc.Save(entity);
    }
}

class EntityServiceFactory
{
    public EntityServiceFactory(RepositoryProvider provider)
    {
        m_provider = provider;
    }

    private RepositoryProvider m_provider; // Dependency

    public virtual IEntityService GetEntityService()
    {
        var repository = m_provider.GetRepository<Entity>();
        return new EntityService(repository);
    }
}

class EntityService: IEntityService
{
    public EntityService(IEntityRepository repository)
    {
        m_repository = repository;
    }

    private IEntityRepository m_repository; // Dependency

    public Entity GetEntity(object key)
    {
        if (key == null) throw new ArgumentNullException("key");

        // TODO: Check for cached entity here?

        Entity entity = m_repository.GetByKey(key);
        return entity;
    }

    public Entity Save(Entity entity)
    {
        if (entity == null) throw new ArgumentNullException(entity);

        if (entity.Key == null)
        {
            entity = m_repository.Insert(entity);
        }
        else
        {
            m_repository.Update(entity);
        }

        return entity;
    }
}

class RepositoryProvider
{
    public virtual object GetRepository<T>()
    {
        if (typeof(T) == typeof(Entity))
            return new EntityRepository();
        else if (...)
            // ... etc.
    }
}

interface IEntityRepository
{
    Entity GetByKey(object key);
    Entity Insert(Entity entity);
    void Update(Entity entity);
}

class EntityRepository: IEntityRepository
{
    public Entity GetByKey(object key)
    {
        // TODO: Load up an entity from a database here
    }

    public Entity Insert(Entity entity)
    {
        // TODO: Insert entity into database here
    }

    public void Update(Entity entity)
    {
        // TODO: Update existing entity in database here
    }
}
jrista
  • 32,447
  • 15
  • 90
  • 130
  • Thank you for this very thorough explanation. I definitely need to do more research on this. – Chris Thompson Jun 24 '09 at 03:19
  • Your very welcome. :) I haven't had a chance to do my StackOverflow rounds for a while...you got the benefit of my first answer in a few days. – jrista Jun 24 '09 at 03:28
1

Dependency Injection is a great principle that allows you to create tests easily by defining mock objects where needed.

Basically the idea is that you pass in any dependency to an object, it doesn't create its own objects to operate on.

Kekoa
  • 27,892
  • 14
  • 72
  • 91
-1

use a Mock framework to supply test data

http://ayende.com/projects/rhino-mocks.aspx
http://code.google.com/p/moq/
Rony
  • 9,331
  • 2
  • 22
  • 22