C# 如何测试 ModelState?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/286124/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 21:41:02  来源:igfitidea点击:

How can I test ModelState?

c#asp.net-mvc

提问by eKek0

How can I test Controller.ViewData.ModelState? I would prefer to do it without any mock framework.

我该如何测试Controller.ViewData.ModelState?我宁愿在没有任何模拟框架的情况下进行。

采纳答案by Scott Hanselman

You don't have to use a Mock if you're using the Repository Pattern for your data, of course.

当然,如果您对数据使用存储库模式,则不必使用 Mock。

Some examples: http://www.singingeels.com/Articles/Test_Driven_Development_with_ASPNET_MVC.aspx

一些例子:http: //www.singingeels.com/Articles/Test_Driven_Development_with_ASPNET_MVC.aspx

// Test for required "FirstName".
   controller.ViewData.ModelState.Clear();

   newCustomer = new Customer
   {
       FirstName = "",
       LastName = "Smith",
       Zip = "34275",    
   };

   controller.Create(newCustomer);

   // Make sure that our validation found the error!
   Assert.IsTrue(controller.ViewData.ModelState.Count == 1, 
                 "FirstName must be required.");

回答by VaSSaV

//[Required]
//public string Name { get; set; }
//[Required]
//public string Description { get; set; }

ProductModelEdit model = new ProductModelEdit() ;
//Init ModelState
var modelBinder = new ModelBindingContext()
{
    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                      () => model, model.GetType()),
    ValueProvider=new NameValueCollectionValueProvider(
                        new NameValueCollection(), CultureInfo.InvariantCulture)
};
var binder=new DefaultModelBinder().BindModel(
                 new ControllerContext(),modelBinder );
ProductController.ModelState.Clear();
ProductController.ModelState.Merge(modelBinder.ModelState);

ViewResult result = (ViewResult)ProductController.CreateProduct(null,model);
Assert.IsTrue(result.ViewData.ModelState["Name"].Errors.Count > 0);
Assert.True(result.ViewData.ModelState["Description"].Errors.Count > 0);
Assert.True(!result.ViewData.ModelState.IsValid);

回答by Alex Stephens

Adding to the great answers above, check out this fantastic use of the protected TryValidateModel method within the Controller class.

除了上面的好答案之外,请查看 Controller 类中受保护的 TryValidateModel 方法的奇妙用法。

Simply create a test class inheriting from controller and pass your model to the TryValidateModel method. Here's the link: http://blog.icanmakethiswork.io/2013/03/unit-testing-modelstate.html

只需创建一个从控制器继承的测试类并将您的模型传递给 TryValidateModel 方法。这是链接:http: //blog.icanmakethiswork.io/2013/03/unit-testing-modelstate.html

Full credit goes to John Reilly and Marc Talary for this solution.

这个解决方案完全归功于 John Reilly 和 Marc Talary。

回答by Bart Verkoeijen

For testing Web API, use the Validatemethod on the controller:

要测试 Web API,请使用控制器上的Validate方法:

var controller = new MyController();
controller.Configuration = new HttpConfiguration();
var model = new MyModel();

controller.Validate(model);
var result = controller.MyMethod(model);

回答by Paul - Soura Tech LLC

Ran into this problem for .NetCore 2.1 Here's my solution:

.NetCore 2.1 遇到了这个问题 这是我的解决方案:

Extension Method

扩展方法

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace MyExtension
{
    public static void BindViewModel<T>(this Controller controller, T model)
    {
        if (model == null) return;

        var context = new ValidationContext(model, null, null);
        var results = new List<ValidationResult>();

        if (!Validator.TryValidateObject(model, context, results, true))
        {
            controller.ModelState.Clear();
            foreach (ValidationResult result in results)
            {
                var key = result.MemberNames.FirstOrDefault() ?? "";
                controller.ModelState.AddModelError(key, result.ErrorMessage);
            }
        }
    }
}

View Model

查看模型

public class MyViewModel
{
    [Required]
    public string Name { get; set; }
}

Unit Test

单元测试

public async void MyUnitTest()
{
    // helper method to create instance of the Controller
    var controller = this.CreateController();

    var model = new MyViewModel
    {
        Name = null
    };

    // here we call the extension method to validate the model
    // and set the errors to the Controller's ModelState
    controller.BindViewModel(model);

    var result = await controller.ActionName(model);

    Assert.NotNull(result);
    var viewResult = Assert.IsType<BadRequestObjectResult>(result);
}

回答by abovetempo

This not only let's you check that the error exists but also checks that it has the exact same error message as expected. For example both of these parameters are Required so their error message shows as "Required".

这不仅可以让您检查错误是否存在,还可以检查它是否具有与预期完全相同的错误消息。例如,这两个参数都是必需的,因此它们的错误消息显示为“必需”。

Model markup:

模型标记:

//[Required]
//public string Name { get; set; }
//[Required]
//public string Description { get; set; }

Unit test code:

单元测试代码:

ProductModelEdit model = new ProductModelEdit() ;
//Init ModelState
var modelBinder = new ModelBindingContext()
{
    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                      () => model, model.GetType()),
    ValueProvider=new NameValueCollectionValueProvider(
                        new NameValueCollection(), CultureInfo.InvariantCulture)
};
var binder=new DefaultModelBinder().BindModel(
                 new ControllerContext(),modelBinder );
ProductController.ModelState.Clear();
ProductController.ModelState.Merge(modelBinder.ModelState);

ViewResult result = (ViewResult)ProductController.CreateProduct(null,model);
Assert.IsTrue(!result.ViewData.ModelState.IsValid);
//Make sure Name has correct errors
Assert.IsTrue(result.ViewData.ModelState["Name"].Errors.Count > 0);
Assert.AreEqual(result.ViewData.ModelState["Name"].Errors[0].ErrorMessage, "Required");
//Make sure Description has correct errors
Assert.IsTrue(result.ViewData.ModelState["Description"].Errors.Count > 0);
Assert.AreEqual(result.ViewData.ModelState["Description"].Errors[0].ErrorMessage, "Required");