I'm trying to write unit tests for ModelState validation for an Asp.Net Core Web API.
I read that, the best way to do so is to use TryValidateModel
function. But, every time I run the unit test, it throws NullReference exception.
I found many articles suggesting controller.ModelState.AddModelError("","")
, but I'm not interested in this, as I believe that it beats the actual purpose of the real model validation.
[TestMethod]
public void TestMethod1()
{
var controller = new TestController();
controller.Post(new Model());
}
public class TestController : Controller
{
public IActionResult Post(Model model)
{
bool b = TryValidateModel(model)
return Ok();
}
}
TryValidateModel(model)
always throws NullReference Exception from TryValidateModel(model, prefix)
function.
Appreciate any help.
It's configuration/integration issue.
You can see some additional info in the issue in ASP.NET Core repo and another one on github. But I can tell you the easiest fix (I used it once)
var objectValidator = new Mock<IObjectModelValidator>();
objectValidator.Setup(o => o.Validate(It.IsAny<ActionContext>(),
It.IsAny<ValidationStateDictionary>(),
It.IsAny<string>(),
It.IsAny<Object>()));
controller.ObjectValidator = objectValidator.Object;
As I figured how to fix Null Reference Exception thanks to @Egorikas, I noticed that it still doesn't actually validate the model and always returns a true.
I found that we could just use Validator
class in System.ComponentModel.DataAnnotations
namespace.
[TestMethod]
public void TestMethod1()
{
var model = new Person();
var validationResultList = new List<ValidationResult>();
bool b1 = Validator.TryValidateObject(model, new ValidationContext(model), validationResultList);
}
You can directly validate it from the Test method itself, rather than having to call the controller, if ModelState validation is your intention.
Hope this helps.
Based on Andrew Van Den Brink answer's, but with actually having the validation errors set in the ModelState.
private class ObjectValidator : IObjectModelValidator
{
public void Validate(ActionContext actionContext, ValidationStateDictionary validationState, string prefix, object model)
{
var context = new ValidationContext(model, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
bool isValid = Validator.TryValidateObject(
model, context, results,
validateAllProperties: true
);
if (!isValid)
results.ForEach((r) =>
{
// Add validation errors to the ModelState
actionContext.ModelState.AddModelError("", r.ErrorMessage);
});
}
}
Then, simply set the ObjectValidator in your controller:
controller.ObjectValidator = new ObjectValidator();
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