ASP.NET MVC Controller post方法单元测试:ModelState.IsValid始终为true

Cyc*_*eak 34 c# asp.net-mvc unit-testing modelstate

我已经为ASP.NET MVC Web应用程序编写了我的第一个单元测试.一切正常,它给了我有价值的信息,但我不能在视图模型中测试错误.ModelState.IsValid始终为true,即使未填充某些值(空字符串或null).

我已经读过,当发布的数据映射到模型时,模型验证会发生,您需要编写一些代码来自行进行模型验证:

我已经尝试了链接网页中提供的三个示例,但它似乎对我不起作用.

一些代码:

我的观点模型

...
[Required(ErrorMessageResourceName = "ErrorFirstName", ErrorMessageResourceType = typeof(Mui))]
[MaxLength(50)]
[Display(Name = "Firstname", ResourceType = typeof(Mui))]
public string FirstName { get; set; }
...
Run Code Online (Sandbox Code Playgroud)

控制器

...
 [HttpPost]
    public ActionResult Index(POSViewModel model)
    {
        Contract contract = contractService.GetContract(model.ContractGuid.Value);

        if (!contract.IsDirectDebit.ToSafe())
        {
            ModelState.Remove("BankName");
            ModelState.Remove("BankAddress");
            ModelState.Remove("BankZip");
            ModelState.Remove("BankCity");
            ModelState.Remove("AccountNr");
        }

        if (ModelState.IsValid)
        {
            ...

            contractValidationService.Create(contractValidation);
            unitOfWork.SaveChanges();

            return RedirectToAction("index","thanks");
        }
        else
        {
            return Index(model.ContractGuid.ToString());
        }
    }
Run Code Online (Sandbox Code Playgroud)

我的单元测试

  posViewModel.FirstName = null;
  posViewModel.LastName = "";
 ...
 var modelBinder = new ModelBindingContext()
        {
            ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => posViewModel, posViewModel.GetType()),
            ValueProvider = new NameValueCollectionValueProvider(new System.Collections.Specialized.NameValueCollection(), CultureInfo.InvariantCulture)
        };
        var binder = new DefaultModelBinder().BindModel(new ControllerContext(), modelBinder);
        posController.ModelState.Clear();
        posController.ModelState.Merge(modelBinder.ModelState);

        ActionResult result = posController.Index(posViewModel);

        //Assert
        mockContractValidationService.Verify(m => m.Create(It.IsAny<ContractValidation>()), Times.Never);
        Assert.IsInstanceOfType(result, typeof(ViewResult));
Run Code Online (Sandbox Code Playgroud)

在视图中,我正在使用不显眼的JavaScript验证,它可以工作.

Ken*_*eth 86

你试图同时测试两种不同的东西.控制器不能用于验证模型状态,只是根据验证结果的不同行为.因此,控制器的单元测试不应该尝试测试验证,应该在不同的测试中完成.在我看来,你应该有三个单元测试:

  1. 一个验证模型验证是否正确的
  2. 一个验证当modelstate有效时控制器是否正常运行的一个
  3. 一个验证当modelstate无效时控制器是否正常运行的一个

这是你如何做到这一点:

1.模型验证

[Test]
public void test_validation()
{
    var sut = new POSViewModel();
    // Set some properties here
    var context = new ValidationContext(sut, null, null);
    var results = new List<ValidationResult>();
    var isModelStateValid =Validator.TryValidateObject(sut, context, results, true);

    // Assert here
}
Run Code Online (Sandbox Code Playgroud)

2.具有无效模型状态的控制器

[Test]
public void test_controller_with_model_error()
{
    var controller = new PosController();
    controller.ModelState.AddModelError("test", "test");

    ActionResult result = posController.Index(new PosViewModel());

    // Assert that the controller executed the right actions when the model is invalid
}
Run Code Online (Sandbox Code Playgroud)

3.具有有效模型状态的控制器

[Test]
public void test_controller_with_valid_model()
{
    var controller = new PosController();
    controller.ModelState.Clear();

    ActionResult result = posController.Index(new PosViewModel());

    // Assert that the controller executed the right actions when the model is valid
}
Run Code Online (Sandbox Code Playgroud)

  • 不,不是真的,您要测试模型是否设置了正确的验证。你是否想测试它是一个不同的问题,但它绝对是在测试你的代码,而不是框架 (2认同)

Cyc*_*eak 9

我找到了这个解决方案:SO:当我使用Validator.TryValidateObject并结合@Kenneth提供的解决方案时,验证不起作用:

[TestMethod]
    public void test_validation()
    {
        var sut = new POSViewModel();
        // Set some properties here
        var context = new ValidationContext(sut, null, null);
        var results = new List<ValidationResult>();
        TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(POSViewModel), typeof(POSViewModel)), typeof(POSViewModel));

        var isModelStateValid = Validator.TryValidateObject(sut, context, results, true);

        // Assert here
    }
Run Code Online (Sandbox Code Playgroud)

如果您有一个包含所有资源的类库,请不要忘记在测试项目中引用它.