Unit-testing – Can not understand how dependency injection can ease testing inside asp.net MVC

asp.net-mvcdependency-injectionmvcrepositoryunit testing

Each time i read an article or a book about asp.net MVC , there will be a chapter for dependency injection and repository . now i can easily feel the benefits of using repository over hard coding the entity framework code inside the action methods, as using repository i can write the methods which uses the entity framework inside my repository methods and reuse these methods over my action method, so i can easily understand that using Repository will facilitate re-usability .

but when it comes to dependency injection, authors always say that it facilitate testing and unit testing. so they say instead of initiating the repository class inside the controller class i will be initiating an interface of the repository class. and they say this will facilitate the unit testing.. but i can not get my mind on this , mainly why imitating the repository interface inside my controller class will facilitate unit testing while initiating the repository class itself inside my controller class will not !!

can anyone adivce on this?

Best Answer

Consider a simple blog, and a PostsController that shows a blog post.

You enable dependency injection by setting the IPostRepository object using a constructor argument and instead of instantiating a concrete class in the controller:

public class PostsController : Controller
{
    private IPostRepository posts;

    public PostsController(IPostRepository posts)
    {
        if (posts == null)
            throw new ArgumentNullException("posts");

        this.posts = posts;
    }

    public ActionResult Details(int id)
    {
        BlogPost post = posts.Find(id);

        if (post == null)
            return HttpNotFound();

        BlogPostDetails model = new BlogPostDetails(post);

        return View(model);
    }
}

By allowing the posts repository to be injected, we can unit test the logic in the controller by providing a "mock" object. In this case, I'm using Moq, an object mocking library available on NuGet (not an endorsement, just for the sake of completing the example):

[TestClass]
public class BlogPostTests
{
    private IPostRepository mockRepository;

    [TestInitialize]
    public void Setup()
    {
        this.mockRepository = new Moq.Mock<IPostRepository>();
    }

    [TestMethod]
    public void ReturnsView()
    {
        var expectedPost = new BlogPost("Test Title", "<p>Body text</p>", DateTime.Parse("2017/01/13"));

        mockRepository.Setup(posts => posts.Find(1))
            .Returns(expectedPost) // posts.Find(1) will return a test stub
            .Verifiable(); // If posts.Find(1) doesn't get called, test fails

        var controller = new PostsController(mockRepository.Object);
        var result = controller.Details(1);

        // Assert that correct view was returned
    }
}

Now you can disconnect your controller from the rest of the technology stack and just test the "Details" method, making this a true Unit Test. As an added benefit, this test will execute in a millisecond or less. Compare that to a manual functional test run by a human, that will probably take upwards of a minute to set up the data and verify it, or 20-30 seconds for an automated functional test. The unit test will execute faster by an order of magnitude.