views:

152

answers:

3

I'm having a hard time finding information on what I expect to be a pretty straightforward scenario. I'm trying to unit test an Action on my ASP.NET Mvc 2 Controller that utilizes a custom input model w/ DataAnnotions. My testing framework is xUnit, as mentioned in the title.

Here is my custom Input Model:

public class EnterPasswordInputModel
{
    [Required(ErrorMessage = "")]
    public string Username { get; set; }

    [Required(ErrorMessage = "Password is a required field.")]
    public string Password { get; set; }
}

And here is my Controller (took out some logic to simplify for this ex.):

[HttpPost]
public ActionResult EnterPassword(EnterPasswordInputModel enterPasswordInput)
{
    if (!ModelState.IsValid)
        return View();

    // do some logic to validate input
    // if valid - next View on successful validation
        return View("NextViewName");
    // else - add and display error on current view
        return View();
}

And here is my xUnit Fact (also simplified):

[Fact]
public void EnterPassword_WithValidInput_ReturnsNextView()
{
    // Arrange
    var controller = CreateLoginController(userService.Object);

    // Act
    var result = controller.EnterPassword(
        new EnterPasswordInputModel
            {
                Username = username, Password = password
            }) as ViewResult;

    // Assert
    Assert.Equal("NextViewName", result.ViewName);
}

When I run my test I get the following error on my test fact when trying to retrieve the controller result (Act section):

System.NullReferenceException: Object reference not set to an instance of an object.

Thanks in advance for any help you can offer!

A: 

Where are you assigning username? password? In the snippet you are showing they would be null.

Tim Hoolihan
They are constants set earlier in the class, sorry for not including them.
Danny Douglass
A: 

You're dereferencing a null instance inside your controller action. Probably in the code you took out to "simplify" the question. Look at the call stack in the test results to figure out what. You may need to mock something for the test.

Craig Stuntz
Smack on my original error! The real problem was my Model not being validated using ModelState.IsValid in the controller action. My response below expands on this...
Danny Douglass
+1  A: 

I think I'm on the track to a solution though. Here is the change I made to my controller:

Original

if (!ModelState.IsValid)
    return View();

Updated

if (!TryUpdateModel(loginInput))
            return View();

It seems that model binding was not occurring during my test. It appears that the model binding does not take place unless a POST occurs. By forcing the attempted model binding I was able to get the test to pass.

Note: There was also an error in my action that was causing my original null reference that I caused while trying to figure out why my model wasn't being validated.

Reference: http://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.html

Danny Douglass
whoops - for the Stack Overflow example my updated should have used "enterPasswordInput" and not "loginInput". The later is used in my real code. =P
Danny Douglass