简体   繁体   中英

Setup Mocked ViewModel for Unit Testing

Here is the scenario:

I'm writing a test for my controller and need to setup a view model titled CheckoutViewModel . My controller method, Products does not take CheckoutViewModel as a parameter, so I cannot pass it in that way.

Currently, the test fails returning a Null Exception because CheckoutViewModel is not getting set and called.

Question: How can I setup my CheckoutViewModel with data.

Error Details:

  • System.NullReferenceException

  • Object reference not set to an instance of an object

Current Test

[TestMethod]
public void Products_ProductControllerIsCalled_ReturnsViewWithProducts()
{
    // Arrange
    var currentSession = _autoMoqer.GetMock<ICurrentSession>().Object;
    ProductController productController = new ProductController(currentSession);

    var checkoutViewModel = new CheckoutViewModel
    {
        CheckoutId = new Guid()
    };

    // Act
    ActionResult result = productController.Products();

    // Assert
    Assert.IsInstanceOfType(result, typeof(ViewResult));
}

Controller

 [AccectReadVerbs]
 public ActionResult Products()
 {
    CheckoutViewModel checkoutViewModel = GetCheckoutViewModel();
    var checkoutId = checkoutViewModel.CheckoutId;
    var result = _productOrchestrator.Products(checkoutId, currentSession)

    return View(result);
 }

Failing on this method

private CheckoutViewModel GetCheckoutViewModel()
{
    if(Session["CheckoutViewModel"] == null)
    {
        return new CheckoutViewModel();
    }
    return (CheckoutViewModel)Session["CheckoutViewModel"];
}

If GetCheckoutViewModel has some dependencies on ie services, dbConnection or other complex classes, you need to add a class with an interface, move the method for GetCheckOutViewModel to the class and take the new interface as a dependency to the controller. Then you need to mock the new interface.

Or edit your viewmodel to take interface dependencies on the stuff that stands in the way of unit testing, ie the Session.

I think you could create some interface:

public interface ISessionManager { Session session {get; set;} }

Then your controller constructor:

public ProductsController(ISessionManager sm) { _sessionManager = sm; }

Then you can pass a mocked instance to your controller.

I'm guessing that the exceptions is due to the fact that when you're running the unit test there will not be any (webserver) session available. What you want do is to isolate your tests from any external dependencies - and a session state that is part of the webserver hosting environment would be an external dependency.

To solve this you need to either mock or stub out the Session object from your test. There are many ways to do this, but the easiest way would be to make Session a public property on the Controller. From your test you would then set the Session to an instance you create within your test.

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