I'm trying to write an XUnit test to test my custom validator. The validator checks the value of other property which indicates if the validated property should be null or have a value. However the test returns ArgumentNullException when I'm using TryValidateProperty method.
Validator:
public class ConcatenatedDataValidator : ValidationAttribute
{
public string PropertyName { get; private set; }
public ConcatenatedDataValidator(string propertyName)
{
this.PropertyName = propertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var property = validationContext.ObjectType.GetProperty(PropertyName);
if(property == null && value != null)
{
return new ValidationResult(string.Format("{0} is null", PropertyName));
}
var chosenValue = property.GetValue(validationContext.ObjectInstance, null);
if(chosenValue.Equals("00") && (value == null || value.Equals(string.Empty))
|| chosenValue.Equals("01") && value != null)
{
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
}
Test:
public class ConcatenatedDataValidatorTests
{
private TestedModel model;
private ValidationContext context;
private List<ValidationResult> results;
[Fact]
public void IsValid_OtherValueIs00ThisValueIsNull_ReturnFalse()
{
// arrange
var concatenatedDataValidator = new ConcatenatedDataValidator("OtherProperty");
model = new TestedModel();
model.OtherProperty = "00";
model.ThisProperty = null;
context = new ValidationContext(model);
results = new List<ValidationResult>();
// act
var result = Validator.TryValidateProperty(model.ThisProperty, context, results);
// assert
Assert.False(result);
}
}
The test returns
System.ArgumentNullException : Value cannot be null. Parameter name: propertyName
in the act part. I'd like to test just this one property, as in the model I have plenty of other properties with Required attribute and I wish to keep the tests as simple as possible and test only my custom validator. Is there any way to solve this problem?
This is expected behaviour. As the Validator.TryValidateProperty
specifies that if value
is null
the System.ArgumentNullException
is thrown.
If you want to test this behaviour / the case of your propertie's value being null
then you should catch the exception and check for it - although thats basically testing the .NET framework.
This also indicates that you can cut out the value == null
check in your IsValid
method as it will never trigger.
UPDATE
The whole error refers to the private method EnsureValidPropertyType
called inside TryValidateProperty
(see here).
This is caused because of ValidationContext.MemberName
.
To solve the issue, you have to set the MemberName
during the creation of your ValidationContext (if .NET 4.7.2 and earlier)
ValidationContext context = new ValidationContext(model)
{
MemberName = "ThisProperty"
};
or change the default behaviour in your app config (.NET 4.8).
<configuration>
<appSettings>
<add key="aspnet:GetValidationMemberName" value="true" />
</appSettings>
</configuration>