Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should you unit test with repository classes in MVC3?

I'm trying to do a test on my controllers which get data from repository classes. This is the part of the repository I want to test:

public class NewsRepository
{
    public IEnumerable<NewsItem> GetNews()
    {
        var result = (from n in n_db.NewsItems
                     orderby n.ID descending
                     select n).Take(3);
        return result;
    }
}

Just some small code to get how the testing works. In my HomeController I've got this code inside the Index():

    public ActionResult Index()
    {
        ViewBag.Message = "Announcements";
        NewsRepository n_rep = new NewsRepository();
        var model = i_rep.GetNews();

        return View(model);
    }

I am completely new to testing so all explanations would be great. Thanks.

like image 689
Mappan Avatar asked May 14 '13 10:05

Mappan


People also ask

Can unit testing be automated?

Unit testing can be done manually but is usually automated. Unit testing is a part of the test-driven development (TDD) methodology that requires developers to first write failing unit tests. Then they write code in order to change the application until the test passes.

How to run test project in visual studio?

To run all the tests in a default group, choose the Run icon and then choose the group on the menu. Select the individual tests that you want to run, open the right-click menu for a selected test and then choose Run Selected Tests (or press Ctrl + R, T).


1 Answers

Your controller is impossible to be unit tested in isolation because it is strongly coupled with your repository on the following line:

NewsRepository n_rep = new NewsRepository();

You have simply hardcoded a specific implementation of the repository and in your unit test you cannot mock it. In order to do this properly you should start by defining an abstraction over this repository:

public interface INewsRepository
{
    IEnumerable<NewsItem> GetNews();
}

and then have your specific repository implement this interface:

public class NewsRepository : INewsRepository
{
    ...
}

Ok now that we have an abstraction let's weaken the coupling between your data access and controller logic by using this abstraction:

public class NewsController: Controller
{
    private readonly INewsRepository repository;
    public NewsController(INewsRepository repository)
    {
        this.repository = repository;
    }

    public ActionResult Index()
    {
        ViewBag.Message = "Announcements";
        var model = this.repository.GetNews();
        return View(model);
    }    
}

Alright, now you have a controller that is no longer tightly coupled with some specific implementation. You could pickup your favorite mock framework and write a unit test. For example with NSubstitute here's how the unit test for the Index action might look like:

[TestMethod]
public void Index_Action_Fetches_Model_From_Repo()
{
    // arrange
    var repo = Substitute.For<INewsRepository>();
    IEnumerable<NewsItem> expectedNews = new[] { new NewsItem() };
    repo.GetNews().Returns(expectedNews);
    var sut = new NewsController(repo);

    // act
    var actual = sut.Index();

    // assert
    Assert.IsInstanceOfType(actual, typeof(ViewResult));
    var viewResult = actual as ViewResult;
    Assert.AreEqual(expectedNews, viewResult.Model);
}

And that's pretty much it. Your controller is now easily unit testable in isolation. You don't need to be setting up databases or whatever. That's not the point to test the controller logic.

like image 187
Darin Dimitrov Avatar answered Oct 15 '22 09:10

Darin Dimitrov