C#MVC如何测试Cutom模型验证

时间:2015-08-11 15:09:37

标签: c# validation unit-testing model-view-controller

我有一个名为:requiredIf的自定义属性。此属性与名为RequiredIfValidator的自定义DataAnnotationsModelValidator相关。

我在Global.asax.cs文件中声明了这个映射:

DataAnnotationsModelValidatorProvider.RegisterAdapter( typeof( RequiredIfAttribute ), typeof( RequiredIfValidator ) );

在运行时它可以正常工作:)

但我想通过单元测试来测试我的模型的验证。猜猜比我们有以下

public class MyModel
{
    public bool A {get;set;}

    [RequiredIf ("A", true)]
    public bool? B {get;set;} 
}

当A为假时,此模型有效,当A为真时,B需要设置为true或false。

我尝试使用以下单元测试来测试此验证:

var viewModel = new MyModel();
var context = new ValidationContext( viewModel, null, null );
var results = new List<ValidationResult>();
viewModel.A = false;
var isModelStateValid = Validator.TryValidateObject( viewModel, context, results, true );

Assert.IsFalse( isModelStateValid );

断言失败了。这是因为我的RequiredIfValidator没有设置。所以我的问题是如何设置这个自定义验证器来运行我的单元测试?

谢谢,

1 个答案:

答案 0 :(得分:0)

我设法通过以下扩展方法来使其工作:

public static class ViewModelExtensions
{
    public static IReadOnlyCollection<ValidationResult> GetValidationResults<T>(this T viewModel, Func<Type, object> serviceProvider = null)
    {
        var result = GetComponentValidationResults(viewModel, serviceProvider);

        var modelValidationResults = GetModelValidationResults(viewModel);

        return result
            .Concat(modelValidationResults.ToValidationResults())
            .ToList();
    }

    private static List<ValidationResult> GetComponentValidationResults<T>(T viewModel, Func<Type, object> serviceProvider)
    {
        var vc = new ValidationContext(viewModel);
        if (serviceProvider != null)
        {
            vc.InitializeServiceProvider(serviceProvider);
        }

        var result = new List<ValidationResult>();
        Validator.TryValidateObject(viewModel, vc, result, true);
        return result;
    }

    private static IEnumerable<ModelValidationResult> GetModelValidationResults<T>(T model)
    {
        var modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(T));

        /* build a stub controller context */
        var controllerContext = Fake.ControllerContext.Build();

        var validator = ModelValidator.GetModelValidator(modelMetadata, controllerContext);
        return validator.Validate(null);
    }

    private static IEnumerable<ValidationResult> ToValidationResults(this IEnumerable<ModelValidationResult> results)
    {
        return results.Select(r => r.ToValidationResult());
    }

    private static ValidationResult ToValidationResult(this ModelValidationResult result)
    {
        return new ValidationResult(result.Message, new[] {result.MemberName});
    }
}

可以这样使用:

// arrange
var target = new MyViewModel();

// act
var actual = target.GetValidationResults(StubServiceProvider);

// assert
/* Assertions for whatever the expected validation failure might be */

注意:

  • Fake.ControllerContext.Build()调用是一个工厂,它基于以下内容生成存根控制器上下文:https://stackoverflow.com/a/32672/90609
  • 我设法在我为RequiredAttribute注册了自定义适配器的情况下实现了这一目的。