My Validate method is accessing various services for validation. These services are dependency injected and can be accessed using the validationContext.GetService method. During runtime, this works fine.
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var logic = (ShipRegistrationLogic)validationContext.GetService(typeof(ShipRegistrationLogic));
var userManager = (UserManager<IdentityUser>)validationContext.GetService(typeof(UserManager<IdentityUser>));
var spaceTransitAuthority = (SpaceTransitAuthority)validationContext.GetService(typeof(ISpaceTransitAuthority));
var hull = logic.GetHull(HullId);
var user = userManager.FindByIdAsync(UserId).Result;
if (spaceTransitAuthority.CheckActualHullCapacity(hull) > logic.GetMaxAuthorizedMass(user))
{
yield return new ValidationResult("You do not have the required pilot's license for this hull.", new[] { nameof(HullId) });
}
}
I would like to unit test this complex validation. However, during the execution of the test, I am unable to figure out how to access the services needed for testing the evaluation. As GetService returns null during the test run.
I am using Moq and xUnit, and I have tried mocking the GetService method of the ValidationContext without success, as ValidationContext is a sealed class and cannot be mocked.
This is the test which shows what I have tried:
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void Validate_ShouldPassMassCheck(int hullId)
{
// Arrange
var userId = _users[0].Id;
var viewModel = new ShipRegistrationViewModel()
{
UserId = userId,
HullId = hullId
};
var hull = new Hull()
{
DefaultMaximumTakeOffMass = TakeOffMassEnum.Tank,
Id = hullId,
Name = "Test"
};
var shipRegistrationLogicMock = new Mock<ShipRegistrationLogic>();
var spaceTransitAuthorityMock = new Mock<ISpaceTransitAuthority>();
shipRegistrationLogicMock.Setup(x => x.GetHull(hullId)).Returns(hull);
shipRegistrationLogicMock.Setup(x => x.GetMaxAuthorizedMass(_users[0])).Returns((int)TakeOffMassEnum.Tank);
_userManager.Setup(x => x.FindByNameAsync(userId))
.ReturnsAsync(new IdentityUser()
{
UserName = "user",
});
spaceTransitAuthorityMock.Setup(x => x.CheckActualHullCapacity(hull)).Returns((double)TakeOffMassEnum.Tank);
var context = new Mock<ValidationContext>(viewModel);
context.Setup(x => x.GetService(typeof(ShipRegistrationLogic))).Returns(shipRegistrationLogicMock);
context.Setup(x => x.GetService(typeof(UserManager<IdentityUser>))).Returns(_userManager);
context.Setup(x => x.GetService(typeof(ISpaceTransitAuthority))).Returns(spaceTransitAuthorityMock);
// Act
var results = viewModel.Validate(context.Object);
// Assert
Assert.Single(results);
Assert.Equal(ValidationResult.Success, results.First());
}