在测试我的控制器动作时,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有效?
答案 0 :(得分:17)
当发布的数据绑定到视图模型时,将进行验证。然后将视图模型传递到控制器中。您正在跳过第1部分并将视图模型直接传递给控制器。
您可以使用
手动验证视图模型System.ComponentModel.DataAnnotations.Validator.TryValidateObject()
答案 1 :(得分:10)
I have come across the same issue虽然这里接受的答案确实解决了“无验证”问题,但确实给我带来了一个很大的负面影响:当出现验证错误而不是简单地设置{时,它会抛出异常{1}}至ModelState.Invalid
。
我只在Web Api 2中对此进行了测试,因此我不知道哪些项目可用,但有一个方法ApiController.Validate(object)
强制对传递的对象进行验证,并仅将false
设置为ModelState.IsValid
。此外,您还必须实例化false
属性。
将此代码添加到我的单元测试允许它工作:
Configuration
答案 2 :(得分:4)
另一方面。您应该实际测试控制器返回的内容以及返回的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);
}
现在您知道了,您的模型是正确的,您可以继续使用您的控制器在单独的测试中测试模型,以检查它是否返回正确的结果。此外,您可以使用绑定的模型值来测试验证属性。
通过这种方式,您可以获得一整套测试,如果您的应用程序爆炸,它将在哪个级别实际显示。模型绑定,控制器或验证。
答案 3 :(得分:3)
modelState总是给出错误的
controller.ModelState.AddModelError("key", "error message");
var invalidStateResult = _controller.Index();
Assert.IsNotNull(invalidStateResult);
答案 4 :(得分:1)
使用controller.UpdateModel
或controller.TryUpdateModel
使用控制器的当前ValueProvider绑定一些数据并触发模型绑定验证,然后再检查ModelState.IsValid
答案 5 :(得分:0)
如果要测试验证操作的行为,可以直接添加ModelStateError:
ModelState.AddModelError("Password", "The Password field is required");
答案 6 :(得分:-2)
尝试使用控制器。 ViewModel .ModelState.IsValid而不是controller.ModelState.IsValid。