Blingers
Blingers

Reputation: 883

With FluentValidation how can I test using validationContext within a controller

I have a validator set up that needs to use values outside of the viewmodel being validated. So to do this I use the ValidationContext and assign RootContextData and then call validate method within the controller, if it returns an error I add it to the modelstate. This all works fine but I can't work out how to test it, or maybe this is flagging that I haven't done it in the best way.

E.g. the validator:

RuleFor(x => x.StartDate.Date.Day)
    .Custom((day, context) =>
    {
        if (!context.RootContextData.TryGetValue("TargetDate", out var targetDate)) return;
        
        var dateVm = context.InstanceToValidate;
        if (DatesHelper.SourceDateStringIsGreaterThanTargetDateString(
            dateVm.StartDate.DateInputAsString(),
            targetDate as string) == true)
        {
            context.AddFailure("The Start date must be on or before the target date for the action");
        }
    });

And then in the controller..

. . .

var repositoryResult = customerRepo.Result;
if (!ModelState.IsValid)
{
    return View(vm);
}
var validationContext = new ValidationContext<StartDateViewModel>(vm)
{
    RootContextData =
    {
        ["TargetDate"] = repositoryResult.Dates.Target
    }
};
var validator = new StartDateValidator();
var validationResult = await validator.ValidateAsync(validationContext);
if (!validationResult.IsValid)
{
    ModelState.AddModelError("StartDate.Date.Day", validationResult.Errors.First().ErrorMessage);
    return View(vm);
}

. . .

Obviously I could just pass in a view model with the incorrect dates which will flag this but then it feels like I'm testing the validator within the controller.. What I really want to do (i think) is to pass a viewmodel with arbitrary dates, get the validator to fail on that rule and then assert that the error has been added to modelstate. Any help is appreciated.

Upvotes: 0

Views: 1527

Answers (1)

Stefano D&#39;Onofrio
Stefano D&#39;Onofrio

Reputation: 21

I think what you can do is Test the Controller logic. An example might be something like this:

[Test]
public void IndexPost_AddModelStateError_WhenInvalidData()
{
  var controller = new HomeController();
  var vm = ... //Test Data
  
  var result = controller.Index(vm) as ViewResult;  

  Assert.IsTrue(result.ViewData.ModelState["StartDate.Date.Day"].Errors.Any());          
}

Here you can find the Microsoft documentation about testing the controller logic

Upvotes: 1

Related Questions