In this lesson, you will learn how to isolate your custom validation logic from the MVC pipeline to verify business rules independently and efficiently.
Why Isolate Validation?
When you decorate properties with custom ValidationAttribute classes, the ASP.NET Core framework handles the execution during the model binding phase. However, relying solely on integration tests that trigger the entire MVC pipeline is slow and masks logic errors. To achieve high-quality unit tests, you should treat these attributes as pure logic components that can be executed in isolation.
Testing Without the Pipeline
Since ValidationAttribute provides an IsValid(object value, ValidationContext validationContext) method, you don't need a running web server to test them. You can instantiate the attribute and the context manually in a standard unit test.
Consider a DateNotInFutureAttribute:
[Test]
public void IsValid_FutureDate_ReturnsValidationResult()
{
// Arrange
var attribute = new DateNotInFutureAttribute();
var futureDate = DateTime.Now.AddDays(1);
var context = new ValidationContext(new { Date = futureDate });
// Act
var result = attribute.GetValidationResult(futureDate, context);
// Assert
Assert.IsNotNull(result);
Assert.AreEqual("Date cannot be in the future.", result.ErrorMessage);
}
The Mechanism
By creating a ValidationContext and passing it directly to the attribute, you bypass the complexity of model binding, dependency injection, and HTTP context. This approach is powerful because it allows you to test edge cases—such as null values, unexpected types, or boundary conditions—without the overhead of spinning up the framework.
If your attribute relies on external services (like a database check), you can use the ValidationContext.GetService(typeof(T)) method to inject a mock or service inside your unit test. This keeps your tests fast while ensuring that even complex, database-dependent validation logic remains strictly unit-testable.
Key Takeaway: By manually invoking the GetValidationResult method with a custom ValidationContext, you can verify complex business rules in milliseconds without the overhead of the full MVC pipeline.