tags:

views:

718

answers:

2

At my job we are using Moq for mocking and Unity for an IOC container. I am fairly new to this and do not have many resources at work to help me out with determining the best practices I should use.

Right now, I have a group of repository interfaces (Ex: IRepository1, IRepository2... IRepository4) that a particular process needs to use to do its job.

In the actual code I can determine all of the IRepository objects by using the IOC container and using the RegisterType() method.

I am trying to figure out the best way to be able to test the method that needs the 4 mentioned repositories.

I was thinking I could just register a new instance of the Unity IOC container and call RegisterInstance on the container for each mock object passing in the Mock.Object value for each one. I am trying to make this registration process reusable so I do not have to keep doing the same thing over and over with each unit test unless a unit test requires some specific data to come back from the repository. This is where the problem lies... what is the best practice for setting up expected values on a mocked repository? It seems like if I just call RegisterType on the Unity container that I would lose a reference to the actual Mock object and would not be able to override behavior.

+1  A: 

You wouldn't mock your repositories, you'd create stubs instead with hardcoded types as the return values. Then you'd create two Unity configurations, one for live where you'd load in the production concrete types and another for test where you'd load in your in-memory stubs.

This way you also gain a "test mode" where you can run your app against a known, in-memory, data store.

public DogRepository : IDogRepository
{
    List<Dog> _doggies = new List<Dog>() 
                              {
                                  new Dog("Spot", "Labrador"),
                                  new Dog("Happy", "Werewolf")
                              };

   public GetDogByName( string dogName )
   {
       return _doggies.Where( @d => @d.Name == dogName );
   }

}
jfar
Creating such *Fake* Repositories are one possibility, but not a particularly good option. There's a lot of maintainance associated with these, but first of all the problem is that "known test data" translates to a well-known test anti-pattern called a *General Fixture*: http://xunitpatterns.com/Obscure%20Test.html#General Fixture
Mark Seemann
Wow, thanks for that link. Oops.
jfar
+6  A: 

Unit tests should not use the container at all. Dependency Injection (DI) comes in two phases:

  1. Use DI patterns to inject dependencies into consumers. You don't need a container to do that.
  2. At the application's Composition Root, use a DI Container (or Poor Man's DI) to wire all components together.

How not to use any DI Container at all for unit testing

As an example, consider a class that uses IRepository1. By using the Constructor Injection pattern, we can make the dependency an invariant of the class.

public class SomeClass
{
    private readonly IRepository1 repository;

    public SomeClass(IRepository1 repository)
    {
        if (repository == null)
        {
            throw new ArgumentNullException("repository");
        }

        this.repository = repository;
    }

    // More members...
}

Notice that the readonly keyword combined with the Guard Clause guarantees that the repository field isn't null if the instance was successfully instantiated.

You don't need a container to create a new instance of MyClass. You can do that directly from a unit test using Moq or another Test Double:

[TestMethod]
public void Test6()
{
    var repStub = new Mock<IRepository1>();
    var sut = new SomeClass(repStub.Object);
    // The rest of the test...
}

See here for more information...

How to use Unity for unit testing

However, if you absolutely must use Unity in your tests, you can create the container and use the RegisterInstance method:

[TestMethod]
public void Test7()
{
    var repMock = new Mock<IRepository1>();

    var container = new UnityContainer();
    container.RegisterInstance<IRepository1>(repMock.Object);

    var sut = container.Resolve<SomeClass>();
    // The rest of the test...
}
Mark Seemann
Thanks! I was just looking at things the wrong way.
Rob Packwood