Question

I am writing a unit test for a controller like this:

public HttpResponseMessage PostLogin(LoginModel model)
{
    if (!ModelState.IsValid)
        return new HttpResponseMessage(HttpStatusCode.BadRequest);
}

the model looks like:

public class LoginModel
{
    [Required]
    public string Username { set; get; }
    [Required]
    public string Password { set; get; }
}

Then I have unit test like this one:

[TestMethod]
public void TestLogin_InvalidModel()
{
    AccountController controller = CreateAccountController();

    ...
    var response = controller.PostLogin(new LoginModel() {  });

    Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);

}

Actually the ModelState is validated... which is weird for me as both fields are required... Could anybody advise?

Was it helpful?

Solution

The reason the model state is valid is that a new model state is created when you new up a controller. Web API isn't doing the parameter binding for you here, so it doesn't even have a chance to add model state errors.

If you want to keep this as a unit test, then you should add the model state errors yourself and test what happens.

If you want to test that the model state would be invalid on a real request, I recommend you read this blog post:

http://blogs.msdn.com/b/youssefm/archive/2013/01/28/writing-tests-for-an-asp-net-webapi-service.aspx

and try testing against an in-memory server. One minor note for your case would be that you may want to use a StringContent instead of an ObjectContent on the request to make sure that Web API tries to deserialize and bind the body properly.

OTHER TIPS

TL;DR If you don't want to read the entire article provided by Youssef and want a quick solution to how to make ModelState.IsValid return false. Do this.

[TestMethod]
public void TestLogin_InvalidModel()
{
    AccountController controller = CreateAccountController();
    // new code added -->
    controller.ModelState.AddModelError("fakeError", "fakeError");
    // end of new code
    ...
    var response = controller.PostLogin(new LoginModel() {  });

    Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);

}

Now I can imagine the CreateAccountController() looks something like this for minimum ->

return new AccountApiController()
{
    Request = new HttpRequestMessage(),
    Configuration = new HttpConfiguration()
};

Hope this gives a quick answer for those googling :)

As mentioned before, you need integration tests to validate the ModelState. So, with Asp.Net Core, I'm digging this question to add a simple solution for integrating tests with Asp.Net Core and validation of ModelState

Add the package Microsoft.AspNetCore.TestHost and you can submit requests this simple:

var server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
var client = server.CreateClient();
var model = new { Name = String.Empty };
var content = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json");
var result = await client.PostAsync("/api/yourApiEndpoint", content);
result.StatusCode.Should().Be(HttpStatusCode.BadRequest);

You can find more about it here: http://asp.net-hacker.rocks/2017/09/27/testing-aspnetcore.html

Hope it helps.

I used the following to validate the model state in unit test Visual studio 2017, C#, NET 4.x.x

   [TestMethod]
        public void TestYourValidationModel()
        {
            var configuration = new HttpConfiguration();
            configuration.Filters.Add(new ValidateModelAttribute());
            // Get the quote
            var controller = new YourController
            {
                Request = new HttpRequestMessage(),
                Configuration = configuration
            };
            var request = YourRequestObject;
            controller.Request.Content = new ObjectContent<YourRequestType>(
                request, new JsonMediaTypeFormatter(), "application/json");
            controller.Validate(request);
            Assert.IsTrue(controller.ModelState.IsValid, "This must be valid");
        }

The example is for a request in JSON format. Substitute YourController for the name of your controller, and YourRequesType, for the object type of your request.

This give you the option to test your model for validation without go to the service.

I could not get response.StatusCode property on the response object. So I had to assert as below, which works good for me.

IHttpActionResult actionResult = controller.ActionMethod(request);

Assert.IsInstanceOf(actionResult);

Is there a way to check status code on the response object ? Like for example. Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top