Reputation: 51
Currently we are setting up a new project and like to use the new records introduced in C# 9. We encounter a problem with DataAnnotations inside the record (constructor) not being triggered during the unittest.
Now the DataAnnotation is triggered when calling the Controller, but when i try to simulate this in a unittest (see code below) it will never return any errors.
//Unit Testing ASP.NET DataAnnotations validation
//http://stackoverflow.com/questions/2167811/unit-testing-asp-net-dataannotations-validation
protected static IList<ValidationResult> ValidateModel(object model)
{
var validationResults = new List<ValidationResult>();
var ctx = new ValidationContext(model, null, null);
Validator.TryValidateObject(model, ctx, validationResults, true);
return validationResults;
}
Currently we created a workaround:
public record FooRecord(string BarProperty)
{
[Required]
public string BarProperty { get; init; } = BarProperty;
}
But I'm hoping if someone knows why this happens and maybe know how to solve this using the shorthand syntax:
public record FooRecord([Required] BarProperty){ }
Upvotes: 5
Views: 3325
Reputation: 11
In tests, you should use ControllerBase.TryValidateModel
instead of Validator.TryValidateObject
. Additionally, this validation process will be identical to the one used by ASP.NET. Here’s how to do it:
public record FooDto(
[StringLength(6)]
string ProductId
);
public class AspnetRecordAttributesValidationTests
{
private class TestableController : ControllerBase;
private static TestableController CreateController()
{
// Create a service provider with the required ASP.NET services
var services = new ServiceCollection();
services.AddControllers();
var provider = services.BuildServiceProvider();
return new TestableController
{
// Set up the controller with the model validation service
ObjectValidator = provider.GetRequiredService<IObjectModelValidator>()
};
}
[Fact]
public void ProductId_ValidLength_Passes()
{
// Validate the record with ASP.NET model validation
var isValid = CreateController().TryValidateModel(new FooDto("123456"));
Assert.True(isValid);
}
[Fact]
public void ProductId_InvalidLength_Fails()
{
var controller = CreateController();
var isValid = controller.TryValidateModel(new FooDto("123456789"));
Assert.False(isValid);
Assert.Equal(1, controller.ModelState.ErrorCount);
}
}
Upvotes: 1
Reputation: 8007
You can't apply validation attributes [property: ... ]
to your request parameters that undergoes binding & validation, see this question.
You will receive InvalidOperationException(...)
like @SerjG describes in his comment.
It happend to me too and that is the reason why end up in this SO thread.
For details, see this issue.
Upvotes: 0
Reputation: 731
It will work as expected if you define your record as:
public record FooRecord([property: Required] BarProperty){ }
Upvotes: 6