DataAnnotations Validator类未实现非可空字符串隐式必填校验问题
非可空引用类型的DataAnnotations单元测试校验问题解决方案
在ASP.NET Core控制器中,非可空引用类型(比如string)会被框架自动视为必填项,等价于加了[Required(AllowEmptyStrings = true)],但直接用System.ComponentModel.DataAnnotations.Validator做单元测试时,传null却不会触发这个校验——这是因为这个隐式校验是ASP.NET Core MVC层额外实现的,并非原生DataAnnotations的功能。
下面是几种让单元测试和控制器校验行为保持一致的方法:
方法1:显式添加[Required]特性
最简单的方式是给非可空属性手动加上[Required(AllowEmptyStrings = true)],这样原生Validator就能识别并触发校验:
public class YourModel { [Required(AllowEmptyStrings = true)] public string PropertyName { get; set; } }
方法2:复用ASP.NET Core的验证逻辑
如果不想手动加特性,可以模拟框架的验证流程,借助RequiredMemberModelMetadataProvider来识别非可空引用类型的必填规则:
// 配置模型元数据提供者,启用非可空隐式校验 var mvcOptions = new MvcOptions(); mvcOptions.ModelMetadataDetailsProviders.Add(new RequiredMemberModelMetadataProvider()); var metadataProvider = new DefaultModelMetadataProvider(mvcOptions); // 准备待验证的模型和上下文 var model = new YourModel { PropertyName = null }; var validationContext = new ValidationContext(model) { Items = { { typeof(IModelMetadataProvider), metadataProvider } } }; // 执行校验 var validationResults = new List<ValidationResult>(); var isValid = Validator.TryValidateObject(model, validationContext, validationResults, validateAllProperties: true);
执行后,validationResults里就会包含"The PropertyName field is required"的错误,和控制器中的校验结果一致。
方法3:封装测试辅助方法
可以把上面的逻辑封装成一个工具方法,方便在单元测试中重复使用:
public static bool ValidateWithMvcRules(object model, out List<ValidationResult> results) { var mvcOptions = new MvcOptions(); mvcOptions.ModelMetadataDetailsProviders.Add(new RequiredMemberModelMetadataProvider()); var metadataProvider = new DefaultModelMetadataProvider(mvcOptions); var validationContext = new ValidationContext(model) { Items = { { typeof(IModelMetadataProvider), metadataProvider } } }; results = new List<ValidationResult>(); return Validator.TryValidateObject(model, validationContext, results, validateAllProperties: true); }
单元测试里直接调用:
var model = new YourModel { PropertyName = null }; var isValid = ValidateWithMvcRules(model, out var results); // 断言校验失败且包含指定错误信息 Assert.False(isValid); Assert.Contains(results, r => r.ErrorMessage == "The PropertyName field is required");
关键说明
原生Validator类本身不支持非可空引用类型的隐式校验,这个规则是ASP.NET Core为了适配C# 8+的非可空特性额外添加的。所以要在单元测试中对齐控制器行为,必须借助框架提供的模型元数据扩展。
内容的提问来源于stack exchange,提问作者Scott DePouw
相关产品推荐
相关产品推荐

