views:

296

answers:

4

I'm starting to get into Unit Testing, Dependancy Injection and all that jazz while constructing my latest ASP.NET MVC project.

I'm to the point now where I would like to Unit Test my Controllers and I'm having difficulty figuring out how to appropriately do this without an IoC container.

Take for example a simple controller:

public class QuestionsController : ControllerBase
{
    private IQuestionsRepository _repository = new SqlQuestionsRepository();

    // ... Continue with various controller actions
}

This class is not very unit testable because of its direct instantiation of SqlQuestionsRepository. So, lets go down the Dependancy Injection route and do:

public class QuestionsController : ControllerBase
{
    private IQuestionsRepository _repository;

    public QuestionsController(IQuestionsRepository repository)
    {
        _repository = repository;
    }
}

This seems better. I can now easily write unit tests with a mock IQuestionsRepository. However, what is going to instantiate the controller now? Somewhere further up the call chain SqlQuestionRepository is going to have to be instantiated. It seems as through I've simply shifted the problem elsewhere, not gotten rid of it.

Now, I know this is a good example of where an IoC container can help you by wiring up the Controllers dependancies for me while at the same time keeping my controller easily unit testable.

My question is, how is one suppose to do unit testing on things of this nature without an IoC container?

Note: I'm not opposed to IoC containers, and I'll likely go down that road soon. However, I'm curious what the alternative is for people who don't use them.

A: 

Isn't it possible to keep the direct instantiation of the field and also provide the setter? In this case you'd only be calling the setter during unit testing. Something like this:

public class QuestionsController : ControllerBase
{
    private IQuestionsRepository _repository = new SqlQuestionsRepository();

    // Really only called during unit testing...
    public QuestionsController(IQuestionsRepository repository)
    {
        _repository = repository;
    }
}

I'm not too familiar with .NET but as a side note in Java this is a common way to refactor existing code to improve the testability. I.E., if you have classes that are already in use and need to modify them so as to improve code coverage without breaking existing functionality.

Our team has done this before, and usually we set the visibility of the setter to package-private and keep the package of the test class the same so that it can call the setter.

Peter
@Peter, very good suggestion. Have you had any experience with using IoC containers on your projects or have you not found a need yet?
Simucal
I don't have much .NET experience, most of my work is with Java using Spring for IoC. It has been very useful for improving modularity.
Peter
@Peter: This is pretty much the pattern that I use. I posted an answer that does the same thing, but uses some C# language features that you, being a Java guy, might not be aware of.
Seth Petry-Johnson
+1  A: 

You could have a default constructor with your controller that will have some sort of default behavior.

Something like...

public QuestionsController()
    : this(new QuestionsRepository())
{
}

That way by default when the controller factory is creating a new instance of the controller it will use the default constructor's behavior. Then in your unit tests you could use a mocking framework to pass in a mock into the other constructor.

Chad Moran
+1  A: 

One options is to use fakes.

public class FakeQuestionsRepository : IQuestionsRepository {
    public FakeQuestionsRepository() { } //simple constructor
    //implement the interface, without going to the database
}

[TestFixture] public class QuestionsControllerTest {
    [Test] public void should_be_able_to_instantiate_the_controller() {
        //setup the scenario
        var repository = new FakeQuestionsRepository();
        var controller = new QuestionsController(repository);
        //assert some things on the controller
    }
}

Another options is to use mocks and a mocking framework, which can auto-generate these mocks on the fly.

[TestFixture] public class QuestionsControllerTest {
    [Test] public void should_be_able_to_instantiate_the_controller() {
        //setup the scenario
        var repositoryMock = new Moq.Mock<IQuestionsRepository>();
        repositoryMock
            .SetupGet(o => o.FirstQuestion)
            .Returns(new Question { X = 10 });
        //repositoryMock.Object is of type IQuestionsRepository:
        var controller = new QuestionsController(repositoryMock.Object);
        //assert some things on the controller
    }
}

Regarding where all the objects get constructed. In a unit test, you only set up a minimal set of objects: a real object which is under test, and some faked or mocked dependencies which the real object under test requires. For example, the real object under test is an instance of QuestionsController - it has a dependency on IQuestionsRepository, so we give it either a fake IQuestionsRepository like in the first example or a mock IQuestionsRepository like in the second example.

In the real system, however, you set up the whole of the container at the very top level of the software. In a Web application, for example, you set up the container, wiring up all of the interfaces and the implementing classes, in GlobalApplication.Application_Start.

Justice
A: 

I'm expanding on Peter's answer a bit.

In applications with a lot of entity types, it is not uncommon for a controller to require references to multiple repositories, services, whatever. I find it tedious to manually pass all those dependencies in my test code (especially since a given test may only involve one or two of them). In those scenarios, I prefer setter-injection style IOC over constructor injection. The pattern I use it this:

public class QuestionsController : ControllerBase
{
    private IQuestionsRepository Repository 
    {
        get { return _repo ?? (_repo = IoC.GetInstance<IQuestionsRepository>()); }
        set { _repo = value; }
    }
    private IQuestionsRepository _repo;

    // Don't need anything fancy in the ctor
    public QuestionsController()
    {
    }
}

Replace IoC.GetInstance<> with whatever syntax your particular IOC framework uses.

In production use nothing will invoke the property setter, so the first time the getter is called the controller will call out to your IOC framework, get an instance, and store it.

In test, you just need to call the setter prior to invoking any controller methods:

var controller = new QuestionsController { 
    Repository = MakeANewMockHoweverYouNormallyDo(...); 
}

The benefits of this approach, IMHO:

  1. Still takes advantage of IOC in production.
  2. Easier to manually construct your controllers during testing. You only need to initialize the dependencies your test will actually use.
  3. Possible to create test-specific IOC configurations, if you don't want to manually configure common dependencies.
Seth Petry-Johnson