8

What is the best way to mock below code in unit testing:

public ActionResult Products()
{
      ViewBag.Title = "Company Product";                        
      IEnumerable<ProductDetailDto> productList =   ProductService.GetAllEffectiveProductDetails();
      ProductModels.ProductCategoryListModel model = new ProductModels.ProductCategoryListModel 
      {     
            //the type of ProductDetails => IEnumerable<productDetailDto>  
            ProductDetails = ProductService.GetAllEffectiveProductDetails(),

            //the type of ProductCategoryList => IEnumerable<selectlistitem>
            ProductCategoryList = productList.Select(x => new SelectListItem
            {
                Value = x.FKProductId.ToString(),
                Text = x.Name
            })
      };
      return View(model);
}

FYI, I am working on VS 2012, MVC 4.0, Unit Testing with MOQ object and TFS setup.

Can anyone help me out on this what is the best test method with mock object for above method?

sunil
  • 5,078
  • 6
  • 28
  • 33
Pawan
  • 2,150
  • 11
  • 45
  • 73
  • I guess you probably want to create a Moq `System.Web.HttpContextBase` (setting up Moq User, Request, Response, Session, Cache, Server etc as required). – James S Nov 12 '13 at 11:02
  • yes i want to create MOQ object. – Pawan Nov 12 '13 at 11:04
  • Need bit more information. Are your trying to write a Unit test for the above method? And you trying to mock dependencies such as ProductService? You mentioned "What is the best way to mock below code in unit testing". What below code you exactly want to mock here? – Spock Nov 12 '13 at 11:15
  • >>Yes i am trying to write unit test with moq. >>And i want to know how i can mock dependencies like ProductService in my example ? – Pawan Nov 12 '13 at 11:23

1 Answers1

11

If you want to mock ProductService first you need to inject this dependency.

Constructor injection is the most common approach for controllers in ASP.NET MVC.

public class YourController : Controller
{
    private readonly IProductService ProductService;

    /// <summary>
    /// Constructor injection
    /// </summary>
    public YourController(IProductService productService)
    {
        ProductService = productService;
    }

    /// <summary>
    /// Code of this method has not been changed at all.
    /// </summary>
    public ActionResult Products()
    {
        ViewBag.Title = "Company Product";
        IEnumerable<ProductDetailDto> productList = ProductService.GetAllEffectiveProductDetails();
        ProductModels.ProductCategoryListModel model = new ProductModels.ProductCategoryListModel
        {
            //the type of ProductDetails => IEnumerable<productDetailDto>  
            ProductDetails = ProductService.GetAllEffectiveProductDetails(),

            //the type of ProductCategoryList => IEnumerable<selectlistitem>
            ProductCategoryList = productList.Select(x => new SelectListItem
            {
                Value = x.FKProductId.ToString(),
                Text = x.Name
            })
        };
        return View(model);
    }
}

#region DataModels

public class ProductDetailDto
{
    public int FKProductId { get; set; }
    public string Name { get; set; }
}

public class ProductModels
{
    public class ProductCategoryListModel
    {
        public IEnumerable<ProductDetailDto> ProductDetails { get; set; }
        public IEnumerable<SelectListItem> ProductCategoryList { get; set; }
    }
}

#endregion

#region Services

public interface IProductService
    {
        IEnumerable<ProductDetailDto> GetAllEffectiveProductDetails()
    }

public class ProductService : IProductService
{
    public IEnumerable<ProductDetailDto> GetAllEffectiveProductDetails()
    {
        throw new NotImplementedException();
    }
}

#endregion

Then you easily create a mock instance of IProductService, pass it into constructor of YourController, setup GetAllEffectiveProductDetails method and check returned ActionResult and its model.

[TestClass]
public class YourControllerTest
{
    private Mock<IProductService> productServiceMock;

    private YourController target;

    [TestInitialize]
    public void Init()
    {
        productServiceMock = new Mock<IProductService>();

        target = new YourController(
            productServiceMock.Object);
    }

    [TestMethod]
    public void Products()
    {
        //arrange
        // There is a setup of 'GetAllEffectiveProductDetails'
        // When 'GetAllEffectiveProductDetails' method is invoked 'expectedallProducts' collection is exposed.
        var expectedallProducts = new List<ProductDetailDto> { new ProductDetailDto() };
        productServiceMock
            .Setup(it => it.GetAllEffectiveProductDetails())
            .Returns(expectedallProducts);

        //act
        var result = target.Products();

        //assert
        var model = (result as ViewResult).Model as ProductModels.ProductCategoryListModel;
        Assert.AreEqual(model.ProductDetails, expectedallProducts);
        /* Any other assertions */
    }
}
Community
  • 1
  • 1
Ilya Palkin
  • 14,687
  • 2
  • 23
  • 36
  • 1
    That's exactly the way I would do it too. +1 – hutchonoid Nov 17 '13 at 20:19
  • But in production, will the MVC framework automatically call the controller's constructor with an instance of the IProduceService? – Yngvar Kristiansen Jun 27 '14 at 12:25
  • In order to make MVC call controller's constructor with an instance of the `IProductService` automatically **it is needed to implement custom Controller Factory**, otherwise you'll get ["No parameterless constructor defined for this object" exception](http://stackoverflow.com/questions/21631323/ioc-castle-windsor-no-parameterless-constructor-defined-for-this-object/21638550#21638550). The link below contains an example of the implementation. – Ilya Palkin Jun 27 '14 at 21:36