单元测试中的模型状态验证

时间:2013-06-27 15:09:39

标签: c# unit-testing asp.net-web-api vs-unit-testing-framework model-validation

我正在为这样的控制器编写单元测试:

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

模型看起来像:

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

然后我就像这样进行单元测试:

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

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

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

}

实际上ModelState已经过验证......这对我来说很奇怪,因为这两个字段都是必需的...... 有人可以提出建议吗?

5 个答案:

答案 0 :(得分:27)

模型状态有效的原因是当您新建控制器时会创建新的模型状态。 Web API在这里没有为您执行参数绑定,因此它甚至没有机会添加模型状态错误。

如果你想把它作为一个单元测试,那么你应该自己添加模型状态错误并测试会发生什么。

如果您想测试模型状态在实际请求中无效,我建议您阅读此博文:

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

并尝试针对内存服务器进行测试。您的案例的一个小注意事项是您可能希望在请求中使用StringContent而不是ObjectContent,以确保Web API尝试反序列化并正确绑定正文。

答案 1 :(得分:19)

TL; DR 如果您不想阅读Youssef提供的整篇文章,并希望快速解决如何使ModelState.IsValid返回false。做这个。

[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);

}

现在我可以想象CreateAccountController()看起来像这样最小 - >

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

希望这能为谷歌搜索提供快速解答:)

答案 2 :(得分:9)

如前所述,您需要集成测试来验证ModelState。因此,使用Asp.Net Core,我正在挖掘这个问题,以便为Asp.Net Core集成测试和模型状态验证添加一个简单的解决方案

添加包Microsoft.AspNetCore.TestHost,您可以这么简单地提交请求:

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);

您可以在此处找到更多相关信息: http://asp.net-hacker.rocks/2017/09/27/testing-aspnetcore.html

希望它有所帮助。

答案 3 :(得分:1)

我使用以下内容在单元测试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");
        }

该示例适用于JSON格式的请求。将控制器的名称替换为YourController,将请求的对象类型替换为YourRequesType。

这使您可以选择测试模型以进行验证,而无需使用服务。

答案 4 :(得分:0)

我无法在响应对象上获得 response.StatusCode 属性。所以我不得不断言如下,这对我很有用。

IHttpActionResult actionResult = controller.ActionMethod(request);

Assert.IsInstanceOf(actionResult);

有没有办法检查响应对象上的状态代码? 比如说。 Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);