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
How can I test ModelState?
提问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
回答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");