wenet
wenet

Reputation: 13

Mvc.net Unit test with a nullable parameter

I am new for unit test with Moq and Nunit. I have a simple unit test for getting a product list. But the test result didn't turn out as expected.

ProductManagementController action is:

       public ViewResult Index(int? id)
    {
        return View(_ProductRepo.GetProductList(id));
    }

ProductRepository is:

        public IList<Product> GetProductList(int? id)
    {
        if (id == null)
        {
            return (db.Products).ToList();
        }
        else
        {
            return db.Products.Where(i => i.CategoryId == id).ToList();
        }
    }

I have two tests setup, but only the first test(get all products list) is fine.

[TestFixture]
public class Test_ProductManagement
{
    private List<Product> products;
    private List<Category> categories;
    private Mock<IProductRepository> mockProducts; 
    private ProductManagementController target;

    [TestFixtureSetUp]
    public void Initialize()
    {
        images = new List<Product> {
           new Product{Id = 1, Name = "Boat", CategoryId = 1  },
           new Product{Id = 2, Name = "Picture Frame",CategoryId = 2 }
           };

        categories = new List<Category> {
            new Category { Id = 1, Name = "Outdoors" },
            new Category { Id = 2, Name = "Housewares" }
            };

        mockProducts = new Mock<IProductRepository>();
        mockProducts.Setup(m => m.GetProductList(It.IsAny<int>())).Returns(products);
        target = new ProductManagementController(mockProducts.Object);
    } 

    [Test]
    public void Index_Contains_All_Products()
    {
        //Action
        List<Product> result = ((IEnumerable<Product>)target.Index(It.IsAny<int>()).ViewData.Model).ToList();

        //Assert
        Assert.AreEqual(2, result.Length);
        Assert.AreEqual("Boat", result[0].Name);
        Assert.AreEqual("Picture Frame", result[1].Name);
    }

    [Test]
    public void Index_Get_ImageList_By_CategoryId()
    {   //Arrange
        int id = 2;

        //Action
        List<Product> result = ((IEnumerable<Product>)target.Index(id).ViewData.Model).ToList();

        //Assert
        Assert.AreEqual(1, result.Count());
        Assert.AreEqual("Picture Frame", result[0].Name);
    }

The 2nd test always return a full product list which include 2 products while I only expect 1 returned from Assert.AreEqual(1,result.Count());

I can't figure out why test code always take the id as a null parameter in the above index call: target.Index(id) . However all my project codes run correctly in the browsers.

Does anyone has a clue? Thanks.

Upvotes: 1

Views: 242

Answers (1)

CodeCaster
CodeCaster

Reputation: 151654

I can't figure out why test code always take the id as a null parameter in the above index call: target.Index(id)

It doesn't. You don't show all code (specifically how your controller handles the repository injection) and you seem to have renamed at least the products / images field, but the code works just fine.

You call target.Index(id), which in turn calls _ProductRepo.GetProductList(id). I assume this is your mock being called, which is Setup() by you to always return the entire product list.

The mock does exactly what you ask it to, no ProductRepository is used in this code, so your if (id == null) is never executed.

In order to fix this, you must Setup() your mock differently in each test method, or setup both cases in advance:

mockProducts.Setup(m => m.GetProductList(null)).Returns(products);
mockProducts.Setup(m => m.GetProductList(2)).Returns(new List<Product>{products[1]});

Of course you want to setup the latter call somewhat less specific, but I hope you see where you can fix this.

Upvotes: 1

Related Questions