24

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

为什么当产品没有名称、描述和价格时模型状态有效?

4

7 回答 7

18

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

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

System.ComponentModel.DataAnnotations.Validator.TryValidateObject()
于 2011-11-17T10:01:17.133 回答
10

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

我只在 Web Api 2 中对此进行了测试,所以我不知道哪些项目可以使用它,但是有一种方法ApiController.Validate(object)可以强制对传递的对象进行验证,并且只ModelState.IsValidfalse. 此外,您还必须实例化该Configuration属性。

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

userController.Configuration = new HttpConfiguration();
userController.Validate(addressInfo);
于 2014-11-05T17:26:18.540 回答
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);
}

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

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

于 2012-12-14T16:23:32.563 回答
3
  1. 创建控制器类的实例。
  2. 添加模型状态并调用添加模型状态后
  3. modelState 总是给出错误的

    controller.ModelState.AddModelError("key", "error message");
    
    var invalidStateResult = _controller.Index();
    
    Assert.IsNotNull(invalidStateResult);
    
于 2015-05-24T06:16:35.293 回答
2

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

于 2011-11-22T22:49:03.383 回答
0

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

ModelState.AddModelError("Password", "The Password field is required");
于 2012-08-28T05:02:17.240 回答
-2

试试控制器。ViewModel .ModelState.IsValid 而不是 controller.ModelState.IsValid。

于 2011-11-17T09:54:54.727 回答