In the context of unit testing it is possible to create two controller constructors, one that the controller factory will use by default and another one dedicated for unit testing.
public class ProductController : Controller
{
private IProductRepository repository;
public int PageSize = 10;
// default constructor
public ProductController()
{
this.repository = new ProductRepository();
}
// dedicated for unit testing
public ProductController(IProductRepository productRepository)
{
this.repository = productRepository;
}
public ViewResult List(int page=1)
{
return View(repository.Products
.OrderBy(p => p.ProductID)
.Skip((page - 1) * PageSize)
.Take(PageSize));
}
}
Unit testing can be achieved this way
[TestMethod]
public void Can_Paginate()
{
// Arrange
Mock<IProductRepository> mock = new Mock<IProductRepository>();
mock.Setup(m => m.Products).Returns(new Product[]
{
new Product {ProductID = 1, Name = "P1"},
new Product {ProductID = 2, Name = "P2"},
new Product {ProductID = 3, Name = "P3"},
new Product {ProductID = 4, Name = "P4"},
new Product {ProductID = 5, Name = "P5"}
}.AsQueryable());
ProductController controller = new ProductController(mock.Object);
controller.PageSize = 3;
// Act
IEnumerable<Product> result =
(IEnumerable<Product>)controller.List(2).Model;
// Assert
Product[] prodArray = result.ToArray();
Assert.IsTrue(prodArray.Length == 2);
Assert.AreEqual(prodArray[0].Name, "P4");
Assert.AreEqual(prodArray[1].Name, "P5");
}
In the above I was able to achieve unit testing. My question is why will I choose to use a DI framework (eg. Unity, Ninject, etc.) if I can achieve DI using a dedicated constructor? I must be missing something obvious here.
(BTW the code samples above are mostly from the book Pro ASP.NET MVC 4 book by Adam Freeman, and I modified it some to suit the question I needed to ask)