views:

455

answers:

2

I'm trying to test a very simple form that uses only a list and a create. This is the controller:

public class PositionsController : Controller
{
    private readonly IPositionRepository _positions;

    // default constructor
    public PositionsController()
    {
        _positions = new TestPositionRepository();
    }

    // DI constructor
    public PositionsController(IPositionRepository positions)
    {
        _positions = positions;
    }

    // get a list of all positions
    public ActionResult Index()
    {
        return View(_positions.GetAllPositions());
    }

    // get initial create view
    public ActionResult Create()
    {
        return View();
    } 

    // add the new Position to the list
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Position positionToAdd)
    {
        try
        {
            _positions.AddPosition(positionToAdd);

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
}

TestPositionRepository is simply a mock repository I've created in order to test out dependency injection. Whenever I try to create a new entry, I get sent back to the index view, but the new entry is not added to the list. Using the debugger, it's showing that the constructor is called every time I click on a link or navigate to a link within the controller's control. Is there a way to fix this problem? I have the feeling that I'm doing it wrong. What I'm trying to do is dependency injection using Ninject but I'm stuck on this problem so far.

+5  A: 

Why is this a problem - it's the way ASP.NET requests work. Each request runs up it's own instance of the asp.net page, or the MVC controller, and when the request is done, the controller is discarded - neither of these things persist between requests.

Thus in your create method you should be calling the repository's save/commit method after adding your new position.

blowdart
Ah ok, I didn't know that. I thought that the controllers were only instantiated once per session. The mock repository I have is simply a `List` with some hard-coded entries in it. The `AddPosition` method does `List.Add()`, which should work fine, but because the controller's constructor is called on every refresh, it instantiates a new `List` every time.
Daniel T.
Afraid not - controllers behave just like a WebForms page. For mocking purposes you could put the mock contents in a static class. I wouldn't test against a real repository - that kind of goes against unit testing.
blowdart
A: 

A MockRepository will be stateless in most cases. Thats why you will not see an added entry in Index. I would test Index and Create seperately. For index I would only check if an existing entry is displayed correctly. This means your MockRepository should have some existing entries hardcoded in it for the GetPositions - Method.

If you want to test the flow through the application (what Create + Index already is) I would use an integration test on a real respository.

Malcolm Frexner
Is there no way to have a mock repository keep its state, perhaps as a static class? I'm trying to develop the data classes first and confirm that everything's working, then use the model to design the database tables. My thinking is that it's easier to change classes around than to change tables around, and once the mock repositories work, all you have to do is create a ORM to tie them to the classes.
Daniel T.
There are ways to make a Mock keep state. But it doesnt seem a good way to me. Think about non trivial aspects of ORM you need to take into account like lazy loading of object graphs and deleting of objects that have references. Your mock should behave like the real repository in this scenarios if you want to test a pageflow.There is definitily a place for a mock repository when doing TDD, but maybe you should stick to small parts of your applicationflow when using it.
Malcolm Frexner