Is it possible to test a FluentValidation PropertyValidator
in isolation?
I know I can test the Validator that's using the PropertyValidator
for specific errors but I’d rather test true/false just on the property validator if possible.
Can this be done? If so, how?
As for version 6.2 of FluentValidation it is possible to build the PropertyValidator.Validate() parameter due to making ValidatorSelectors globally configurable: https://github.com/JeremySkinner/FluentValidation/commit/95376c0519da1a06388be91a97fb5062fd4a162e
In the below example you see how I validate the 'puic' property of Track
Unit test:
public void ExistsInCollectionValidatorTest()
{
var track = new Track()
{
puic = "p1"
};
var sut = new ExistsInCollectionValidator<Track>();
// Build PropertyValidator.Validate() parameter
var selector = ValidatorOptions.ValidatorSelectors.DefaultValidatorSelectorFactory();
var context = new ValidationContext(track, new PropertyChain(), selector);
var propertyValidatorContext = new PropertyValidatorContext(context, PropertyRule.Create<Track,string>(t => t.puic), "puic");
var results = sut.Validate(propertyValidatorContext);
// Assertion..
}
I know this has been a while, but I achieved this as follows:
Custom Validator:
public class MyValidator : PropertyValidator
{
public MyValidator ()
: base("Value must be null or between 0 and 3.")
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
if (context.PropertyValue == null)
{
return true;
}
var value = (decimal)context.PropertyValue;
return value >= 0m && value <= 3m;
}
}
Test Validator:
public class TestValidator : InlineValidator<TestObject>
{
public TestValidator (params Action<TestValidator >[] actions)
{
foreach (var action in actions)
{
action(this);
}
}
}
Test Object:
public class TestObject
{
public TestObject(decimal? val)
{
this.GenericDecimal = val;
}
public decimal? GenericDecimal { get; set; }
}
Test:
[Test]
public void TestIt()
{
var validator = new TestValidator(v => v.RuleFor(obj => obj.GenericDecimal).SetValidator( new MyValidator() ));
Assert.IsTrue(validator.Validate(new TestObject(null)).IsValid);
Assert.IsTrue(validator.Validate(new TestObject(0m)).IsValid);
Assert.IsTrue(validator.Validate(new TestObject(3m)).IsValid);
Assert.IsFalse(validator.Validate(new TestObject(-1m)).IsValid);
Assert.IsFalse(validator.Validate(new TestObject(3.01m)).IsValid);
}
I also wanted to test my true / false logic. It is a shame the IsValid method is protected. My work around was to create another IsValid method and have the protected IsValid call through to it.
public class MyValidator: PropertyValidator
{
public MyValidator(
string errorMessage = "default Message") : base(errorMessage)
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
var stringToValidate = context.PropertyValue as String;
return IsValid(stringToValidate);
}
public bool IsValid(string stringToValidate)
{
if (stringToValidate == null)
{
return false;
}
//testing logic here
return true;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With