使用 FluentValidator 验证属性的子项
Using FluentValidator to validate children of properties
我想使用 FluentValidation 来验证一些 classes,其中一个仅用作另一个 属性...但我从未直接创建子 class 所以我想从父级别测试验证。这可能是不必要的/疯狂的
例如我有
public class Parent
{
public string Text {get;set;}
public Child Child {get;set;}
}
public class Child
{
public string Text {get;set;}
}
和
public class ParentValidator : AbstractValidator<Parent>
{
public ParentValidator()
{
RuleFor(p=>p.Text).NotEmpty();
//RuleFor(p=>p.Child).SetValidator(new ChildValidator);
//RuleFor(p=>p.Child.Text).NotEmpty();
}
}
public class ChildValidator : AbstractValidator<Child>
{
public ChildValidator()
{
RuleFor(c=>c.Text).NotEmpty();
}
}
我用
测试
[Test]
public void ParentMustHaveText()
{
new ParentValidator()
.ShouldHaveValidationErrorFor(p => p.Text, "");
}
[Test]
public void ChildMustHaveText()
{
new ParentValidator().ShouldHaveValidationErrorFor(p => p.Child.Text, "");
}
无论我如何设置,ChildMustHaveText
测试总是失败。以这种方式测试我是不是疯了?
因为下面的测试总是通过
[Test]
public void ChildMustHaveText()
{
new ChildValidator().ShouldHaveValidationErrorFor(c => c.Text, "");
}
classes 是 ASP.NET WebApi 项目中的模型。
第一个错误是您忘记在默认 Parent
构造函数中指定 Child
属性 对象的创建 — FluentValidation 尝试动态设置 属性 of [=16] =].
public class Parent
{
public Parent()
{
Child = new Child();
}
public string Text { get; set; }
public Child Child { get; set; }
}
请注意,默认构造函数总是在 ShouldHaveValidationErrorFor
中用于验证前的对象创建。
接下来我发现 ShouldHaveValidationErrorFor
的当前实现不允许检查嵌套级别超过的嵌套属性的有效性1(例如,obj.Child1.Child2.Text
是嵌套的第 3 层)。
陷阱
bug地方源代码(FluentValidation.TestHelper.ValidatorTester
class):
public void ValidateError(T instanceToValidate) {
accessor.Set(instanceToValidate, value);
//
var count = validator.Validate(instanceToValidate, ruleSet: ruleSet).Errors.Count(x => x.PropertyName == accessor.Member.Name);
if (count == 0) {
throw new ValidationTestException(string.Format("Expected a validation error for property {0}", accessor.Member.Name));
}
}
说明
方法将连接的 属性 名称与验证错误 (x.PropertyName
) 与 属性 对象 System.Reflection.RuntimePropertyInfo
名称 (accessor.Member.Name
) 进行比较,例如"Text"
和 "Child.Text"
与 "Text"
两个测试 ,所以测试通过只是因为 parent.Text
是空的,它是无效的并且 属性 两个 class 中的名称彼此相等。
如果简化 — 现在您的测试通过了,但原因不对。
如果重命名其中一个字符串 属性:
,您会看到这种奇怪的行为
public class Child
{
public string Text2 {get;set;}
}
或者如果您使 Parent.Text
属性 在测试中有效(删除规则,或在 Parent()
默认构造函数中初始化非空值)。
public Parent()
{
Child = new Child();
Text = "I like pitfalls";
}
结论
这是 TestHelper class 中的一个错误,我希望这项研究能帮助您为您的应用程序决定未来的测试策略。
永不放弃! ;-)
我想使用 FluentValidation 来验证一些 classes,其中一个仅用作另一个 属性...但我从未直接创建子 class 所以我想从父级别测试验证。这可能是不必要的/疯狂的
例如我有
public class Parent
{
public string Text {get;set;}
public Child Child {get;set;}
}
public class Child
{
public string Text {get;set;}
}
和
public class ParentValidator : AbstractValidator<Parent>
{
public ParentValidator()
{
RuleFor(p=>p.Text).NotEmpty();
//RuleFor(p=>p.Child).SetValidator(new ChildValidator);
//RuleFor(p=>p.Child.Text).NotEmpty();
}
}
public class ChildValidator : AbstractValidator<Child>
{
public ChildValidator()
{
RuleFor(c=>c.Text).NotEmpty();
}
}
我用
测试 [Test]
public void ParentMustHaveText()
{
new ParentValidator()
.ShouldHaveValidationErrorFor(p => p.Text, "");
}
[Test]
public void ChildMustHaveText()
{
new ParentValidator().ShouldHaveValidationErrorFor(p => p.Child.Text, "");
}
无论我如何设置,ChildMustHaveText
测试总是失败。以这种方式测试我是不是疯了?
因为下面的测试总是通过
[Test]
public void ChildMustHaveText()
{
new ChildValidator().ShouldHaveValidationErrorFor(c => c.Text, "");
}
classes 是 ASP.NET WebApi 项目中的模型。
第一个错误是您忘记在默认 Parent
构造函数中指定 Child
属性 对象的创建 — FluentValidation 尝试动态设置 属性 of [=16] =].
public class Parent
{
public Parent()
{
Child = new Child();
}
public string Text { get; set; }
public Child Child { get; set; }
}
请注意,默认构造函数总是在 ShouldHaveValidationErrorFor
中用于验证前的对象创建。
接下来我发现 ShouldHaveValidationErrorFor
的当前实现不允许检查嵌套级别超过的嵌套属性的有效性1(例如,obj.Child1.Child2.Text
是嵌套的第 3 层)。
陷阱
bug地方源代码(FluentValidation.TestHelper.ValidatorTester
class):
public void ValidateError(T instanceToValidate) {
accessor.Set(instanceToValidate, value);
//
var count = validator.Validate(instanceToValidate, ruleSet: ruleSet).Errors.Count(x => x.PropertyName == accessor.Member.Name);
if (count == 0) {
throw new ValidationTestException(string.Format("Expected a validation error for property {0}", accessor.Member.Name));
}
}
说明
方法将连接的 属性 名称与验证错误 (x.PropertyName
) 与 属性 对象 System.Reflection.RuntimePropertyInfo
名称 (accessor.Member.Name
) 进行比较,例如"Text"
和 "Child.Text"
与 "Text"
两个测试 ,所以测试通过只是因为 parent.Text
是空的,它是无效的并且 属性 两个 class 中的名称彼此相等。
如果简化 — 现在您的测试通过了,但原因不对。
如果重命名其中一个字符串 属性:
,您会看到这种奇怪的行为public class Child
{
public string Text2 {get;set;}
}
或者如果您使 Parent.Text
属性 在测试中有效(删除规则,或在 Parent()
默认构造函数中初始化非空值)。
public Parent()
{
Child = new Child();
Text = "I like pitfalls";
}
结论
这是 TestHelper class 中的一个错误,我希望这项研究能帮助您为您的应用程序决定未来的测试策略。
永不放弃! ;-)