【问题标题】:ModelState.IsValid always true when testing Controller in Asp.Net MVC Web Api在 Asp.Net MVC Web Api 中测试控制器时,ModelState.IsValid 始终为真
【发布时间】:2016-09-30 04:40:58
【问题描述】:

我已经尝试过完成这项工作,并进行了许多 google/stackoverflow 搜索,但完全没有运气。

我有一个简单的模型:

public class MovieModel
{
    public string Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Name { get; set; }
}

控制器中的方法:

// POST: api/Movies
public IHttpActionResult Post([FromBody]MovieModel movieModel)
{
    if (ModelState.IsValid)
    {
        //Code
    }
}

还有一个测试方法(是集成测试,但同样会发生在单元测试中):

[TestMethod]
public void MoviesController_Post_Without_Name()
{
    // Arrange
    var model = new MovieModel();
    model.Name = "";

    // Act
    var result = controller.Post(model);

    // Assert
    Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult));
    Assert.AreEqual(6, controller.Get().Count());
}

尽管模型显然无效,但它总是将 IsValid 属性评估为 true。

到目前为止,我尝试了很多方法,但都没有成功。

【问题讨论】:

    标签: c# testing asp.net-web-api modelstate


    【解决方案1】:

    感谢this网站,我找到了解决办法:

    private void SimulateValidation(object model)
    {
        // mimic the behaviour of the model binder which is responsible for Validating the Model
        var validationContext = new ValidationContext(model, null, null);
        var validationResults = new List<ValidationResult>();
        Validator.TryValidateObject(model, validationContext, validationResults, true);
        foreach (var validationResult in validationResults)
        {
            this.controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
        }
    }
    

    并在测试方法中包含这样的一行:

    public void MoviesController_Post_Without_Name()
    {
        // Arrange
        var model = new MovieModel();
        model.Name = "";
    
        // Act
        SimulateValidation(model);
        var result = controller.Post(model);
    
        // Assert
        Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult));
        Assert.AreEqual(6, controller.Get().Count());
    }
    

    希望对某人有所帮助,这样可以节省我在网上搜索的时间。

    【讨论】:

    • 适用于 Core 2.0,对于嵌套只需执行 SimulateValidation(model); SimulateValidation(model.child);
    • 非常感谢@Andre Baptista,这对我有用
    【解决方案2】:

    您的解决方案可能有效,但更好的方法是使用ApiController.Validate 方法。

    public void MoviesController_Post_Without_Name()
    {
        // Arrange
        var model = new MovieModel();
        model.Name = "";
    
        // Act
        controller.Validate(model);   //<---- use the built-in method
        var result = controller.Post(model);
    
        // Assert
        Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult));
        Assert.AreEqual(6, controller.Get().Count());
    }
    

    【讨论】:

    • 我之前试过这个 .Validate 方法,但是不存在。我正在使用 MVC 5。
    • 微软参考显示了 MVC 版本 5 的 Validate 方法,但它根本不起作用,Intellisense 和构建都不起作用。
    • @AndréBaptista 你为什么要谈论 MVC? ApiController 是一个 Web API 类,位于 System.Web.Http 中。确保将正确的 NuGet 包添加到测试项目。
    • 是的,我知道这听起来很奇怪,但我检查了所有内容: - 安装了 nuget 包 (Microsoft.AspNet.WebApi.Core) 并且是 5.0.0 版本,在 Web 和测试项目中都有; - 引用了dll System.Web.Http,在web项目和测试项目中都是5.0.0版本; - using 指令在那里; - 我的控制器继承自 ApiController;当我在 ApiController 上单击“转到定义”(F12 键)时,它会显示方法列表,并且既没有 Validate 也没有 TryValidate 方法。
    【解决方案3】:

    在 WebAPI 5.2.7 上:

    [TestMethod]
    public void MoviesController_Post_Without_Name()()
    {
        // Arrange
        var model = new MovieModel();
        model.Name = "";
    
        controller.Request = new HttpRequestMessage();
        controller.Configuration = new HttpConfiguration();
        controller.Validate(model);
    
        // Act
        var result = controller.Post(model);
    
        // Assert
        ...
    

    这篇文章帮助了我:https://www.c-sharpcorner.com/article/unit-testing-controllers-in-web-api/

    【讨论】:

      【解决方案4】:

      这对我有用:

      public MyResultData Post([FromBody] MyQueryData queryData)
      {
          if (!this.Request.Properties.ContainsKey("MS_HttpConfiguration")) 
          {
              this.Request.Properties["MS_HttpConfiguration"] = new HttpConfiguration();
          }
      
          this.Validate(queryData);
      
          if (ModelState.IsValid)
          {
              DoSomething();
          }
      }
      

      还可以看看这个问题: Validate fails in unit tests

      【讨论】:

        【解决方案5】:

        手动添加模型错误:

        // Arrange
        controller.ModelState.AddModelError("fakeError", "fakeMessage");
        
        // Act
        var result = controller.Post(model);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多