测试ModelState在asp.net mvc中总是有效的

本文关键字:有效 mvc ModelState asp net 测试 | 更新日期: 2023-09-27 18:15:11

在测试控制器的动作时,ModelState总是有效的。

public class Product
{
    public int Id { get; set; }
    [Required]
    [StringLength(10)]
    public string Name { get; set; }
    [Required]
    public string Description { get; set; }
    [Required]
    public decimal Price { get; set; }
}

和我的控制器

public class ProductController : Controller
{
      [HttpPost]
      public ActionResult Create(Product product)
      {
            if (ModelState.IsValid)
            {
                   // Do some creating logic...
                   return RedirectToAction("Display");
            }
             return View(product);              
      }
 }

And test:

[Test]
public TestInvalidProduct()
{
     var product = new Product();
     var controller = new ProductController();
     controller.Create(product);
     //controller.ModelState.IsValid == true
}

当产品没有名称、描述和价格时,为什么modelState是有效的?

测试ModelState在asp.net mvc中总是有效的

当提交的数据绑定到视图模型时进行验证。然后将视图模型传递给控制器。您将跳过第1部分,直接将视图模型传递给控制器。

您可以使用

手动验证视图模型
System.ComponentModel.DataAnnotations.Validator.TryValidateObject()

我也遇到过同样的问题,虽然这里接受的答案确实解决了"无验证"问题,但它确实给我留下了一个很大的负面影响:当存在验证错误时,它会抛出一个异常,而不是简单地将ModelState.Invalid设置为false

我只在Web Api 2中测试了这个,所以我不知道什么项目将有这个可用,但是有一个方法ApiController.Validate(object),它强制对传递的对象进行验证,并且只将ModelState.IsValid设置为false。此外,您还必须实例化Configuration属性。

将这段代码添加到我的单元测试中允许它工作:

userController.Configuration = new HttpConfiguration();
userController.Validate(addressInfo);

还有一点。你应该测试控制器返回什么并且返回的ActionResult是你所期望的。ModelBinder的测试应该单独进行。

假设,您想切换到自定义模型绑定器。您可以将ModelBinder测试重用到您正在创建的新ModelBinder。如果您的业务规则保持不变,您应该能够直接重用相同的测试。但是,如果您混合了Controller测试和ModelBinder测试,并且测试失败,则您不知道问题是在Controller还是在ModelBinder。

假设你像这样测试你的模型绑定:

[Test]
public void Date_Can_Be_Pulled_Via_Provided_Month_Day_Year()
{
    // Arrange
    var formCollection = new NameValueCollection { 
        { "foo.month", "2" },
        { "foo.day", "12" },
        { "foo.year", "1964" }
    };
    var valueProvider = new NameValueCollectionValueProvider(formCollection, null);
    var modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(FwpUser));
    var bindingContext = new ModelBindingContext
    {
        ModelName = "foo",
        ValueProvider = valueProvider,
        ModelMetadata = modelMetadata
    };
    DateAndTimeModelBinder b = new DateAndTimeModelBinder { Month = "month", Day = "day", Year = "year" };
    ControllerContext controllerContext = new ControllerContext();
    // Act
    DateTime result = (DateTime)b.BindModel(controllerContext, bindingContext);
    // Assert
    Assert.AreEqual(DateTime.Parse("1964-02-12 12:00:00 am"), result);
}

现在你知道,你的模型是正确的绑定,你可以继续测试模型与你的控制器在一个单独的测试,以检查它是否返回正确的结果。此外,您可以使用绑定的模型值来测试验证属性。

这样你就可以得到一套完整的测试,如果你的应用程序爆炸了,它会显示在哪个级别上发生了爆炸。

  1. 创建控制器类的实例。
  2. 添加模型状态和调用添加模型状态后
  3. modelState总是给出false

    controller.ModelState.AddModelError("key", "error message");
    var invalidStateResult = _controller.Index();
    Assert.IsNotNull(invalidStateResult);
    

使用controller.UpdateModelcontroller.TryUpdateModel使用控制器的当前ValueProvider绑定一些数据,并在检查ModelState之前触发模型绑定验证。IsValid

如果您想测试验证操作的行为,您可以简单地添加ModelStateError:

ModelState.AddModelError("Password", "The Password field is required");

尝试controller.ViewModel. modelstate。