0

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"];
}
ChaseHardin
  • 2,189
  • 7
  • 29
  • 50
  • Can you show the code for `Products()` from your controller please? – Jason Evans Mar 01 '16 at 15:14
  • Can you debug the unit test, as in step into the code? If so, can you determine whether `_productOrchestrator.Products(checkoutId, currentSession)` actually returns a `result` that isn't `NULL`? I bet that's the problem. – Jason Evans Mar 01 '16 at 15:27
  • Sure, it fails while calling the `GetCheckoutViewModel()` method... It fails specifically on the `if(Session["CheckoutViewModel"] == null)` line. – ChaseHardin Mar 01 '16 at 15:30
  • 2
    Looks liek you need to mock the `Session` object for your unit tests. Take a look at [How do you mock the session object collection using Moq](http://stackoverflow.com/questions/524457/how-do-you-mock-the-session-object-collection-using-moq) as an example. – Jason Evans Mar 01 '16 at 15:39

3 Answers3

0

If GetCheckoutViewModel has some dependencies on i.e 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, i.e the Session.

andreasnico
  • 1,478
  • 14
  • 23
0

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.

brettkc
  • 252
  • 1
  • 9
0

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.

Kjetil Klaussen
  • 6,266
  • 1
  • 35
  • 29