测试 ModelState 在 asp.net mvc 中始终有效

发布于 2024-12-16 14:51:05 字数 978 浏览 1 评论 0原文

测试控制器的操作时,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);              
      }
 }

并测试:

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

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

When testing my controller's actions the ModelState is always valid.

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

And my controller.

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
}

Why the modelState is valid when the product doesn't have a name, Description and price?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

不爱素颜 2024-12-23 14:51:05

当发布的数据绑定到视图模型时,就会发生验证。然后视图模型被传递到控制器中。您将跳过第 1 部分并将视图模型直接传递到控制器中。

您可以使用手动验证视图模型

System.ComponentModel.DataAnnotations.Validator.TryValidateObject()

Validation happens when the posted data is bound to the view model. The view model is then passed into the controller. You are skipping part 1 and passing a view model straight into a controller.

You can manually validate a view model using

System.ComponentModel.DataAnnotations.Validator.TryValidateObject()
甜柠檬 2024-12-23 14:51:05

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

我只在 Web Api 2 中对此进行了测试,因此我不知道哪些项目可以使用此功能,但有一种方法 ApiController.Validate(object) 强制对传递的对象进行验证并仅设置将 ModelState.IsValid 更改为 false。此外,您还必须实例化 Configuration 属性。

将此代码添加到我的单元测试中使其可以工作:

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

I have come across the same issue and while the accepted answer here did solve the "no-validation"-issue, it did leave me with a big negative aspect: it would throw an exception when there were validation errors instead of simply setting ModelState.Invalid to false.

I only tested this in Web Api 2 so I don't know what projects will have this available but there is a method ApiController.Validate(object) which forces validation on the passed object and only sets the ModelState.IsValid to false. Additionally you'll also have to instantiate the Configuration property.

Adding this code to my unit test allowed it to work:

userController.Configuration = new HttpConfiguration();
userController.Validate(addressInfo);
极致的悲 2024-12-23 14:51:05

另一方面。您应该实际测试控制器返回的内容以及返回的 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);
}

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

通过这种方式,您可以获得一整套测试,如果您的应用程序崩溃,这些测试将揭示它实际上在哪个级别执行此操作。模型绑定、控制器或验证。

On another note. You should actually test what the controller returns and that the returned ActionResult is what you expect. Testing the ModelBinder should be done separately.

Let's say, you want to switch to a custom model binder. You could reuse the ModelBinder tests to the new ModelBinder you're creating. If your business rules remain the same, you should be able to directly reuse the same tests. However, if you mix your Controller test and ModelBinder tests and the test fails, you don't know if the problem is in the Controller or the ModelBinder.

Let's say you test your model binding something like this:

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

Now that you KNOW, your model is bound right, you can continue testing the Model with your controller in a separate test to check if it returns you the correct result. Additionally, you can use the bound model values to test your Validation Attributes.

This way you can get a full set of tests which will reveal, if your application blows up, in which level it actually does that. ModelBinding, Controller or Validation.

我的黑色迷你裙 2024-12-23 14:51:05
  1. 创建控制器类的实例。
  2. 添加模型状态并调用添加模型状态后
  3. modelState 总是给出 false

    controller.ModelState.AddModelError("key", "错误信息");
    
    var invalidStateResult = _controller.Index();
    
    Assert.IsNotNull(invalidStateResult);
    
  1. Create Instance of your controller class.
  2. Add model state and call After adding model state
  3. the modelState always give false

    controller.ModelState.AddModelError("key", "error message");
    
    var invalidStateResult = _controller.Index();
    
    Assert.IsNotNull(invalidStateResult);
    
执妄 2024-12-23 14:51:05

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

Use controller.UpdateModel or controller.TryUpdateModel to use the controller's current ValueProvider to bind some data and trigger model binding validation prior to checking if the ModelState.IsValid

初懵 2024-12-23 14:51:05

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

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

If you want to test your validation action's behavior you could simply add ModelStateError:

ModelState.AddModelError("Password", "The Password field is required");
红颜悴 2024-12-23 14:51:05

尝试使用controller.ViewModel.ModelState.IsValid代替controller.ModelState.IsValid。

Try controller.ViewModel.ModelState.IsValid instead of controller.ModelState.IsValid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文