简体   繁体   中英

ViewData.Model is behaving differently in two cases .. UnitTesting failed in MVC4 application

I have two test methods as below, those are testing the same action method. The first one is failing and second one is passing. This is an Asp.net mvc4 application ... Please help me on this ...

//Action method     
public ViewResult Edit(int productID)
{
    Product product = 
    productRepository.Products.FirstOrDefault(p => p.ProductID == productID);           
    return View(product);
}
[TestMethod]
public void Can_Edit_Product() //Failed, result2 is set with product - "P1"
{ 
    //Arrange
    Mock<IProductRepository> mock = new Mock<IProductRepository>();
    mock.Setup(p => p.Products).Returns(new Product[] {
            new Product{ ProductID=1, Name="P1" },
            new Product{ ProductID=2, Name="P2"}
    }.AsQueryable());
    AdminController target = new AdminController(mock.Object);                

    //Act
    Product result1 = target.Edit(1).ViewData.Model as Product;
    Product result2 = target.Edit(3).ViewData.Model as Product;

    //Assert
    Assert.AreEqual("P1", result1.Name);
    Assert.IsNull(result2);
}

[TestMethod]
public void Cannot_Edit_Nonexistant_Product() //Passed
{
    //Arrange
    Mock<IProductRepository> mock = new Mock<IProductRepository>();
    mock.Setup(p => p.Products).Returns(new Product[] {

           new Product{ ProductID=1, Name="P1" },
           new Product{ ProductID=2, Name="P2"}
    }.AsQueryable());
    AdminController target = new AdminController(mock.Object);

    //Act            
    Product result2 = target.Edit(3).ViewData.Model as Product;

    //Assert
    Assert.IsNull(result2);            
}

For the failed test, I am finding that the action method is returning null correctly, but somehow the Model object is not set to null, but it is set to first product. which is really mysterious ...What is going on here ...

[ In the above code productRepository.Products is of type IQueryable ... and I am using Moq for Mocking]

I'd separate the first test up, but it looks like you already know that and you're just asking for an explanation. From what you describe, the controllers ViewData.Model gets set correctly the first time. So target.ViewData.Model is correct. When you set it the second time, perhaps ViewData.Model simply doesn't get overwritten (the framework probably assumes if you're providing null to the view that it can just forget about it because it is null by default). Remember within the context of a web app these actions will be called once and then all view data will be thrown away until the next request. So next request, ViewData.Model will start off as null again. So I would only have one controller action test per test method.

I haven't checked this with the source code but it just seems like a likely explanation to me. You could check what I'm explaining by doing the following.

AdminController target = new AdminController(mock.Object);                

Product result1 = target.Edit(1).ViewData.Model as Product; // ViewData.Model will be product 1 
Product result2 = target.Edit(3).ViewData.Model as Product; // ViewData.Model is still product 1
Product result2 = target.Edit(2).ViewData.Model as Product; // ViewData.Model will be product 2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM