Как мне издеваться над AbstractValidator, который использует наборы правил? - PullRequest
1 голос
/ 16 марта 2020

У меня есть абстрактный валидатор со следующей структурой:

public abstract class RiskAssessmentServiceCreateRequestValidator<T>
    : AbstractValidator<T> where T
        : IRiskAssessmentServiceCreateRequest
{
    public RiskAssessmentServiceCreateRequestValidator(ApplicationContext context)
    {
        RuleSet("modelBinding", () =>
        {
            RuleFor(x => x.ServiceProviderId).NotNull().GreaterThan(0);
        });

        RuleSet("handler", () =>
        {
            //....
        });

    }
}

В моем обработчике запросов я вызываю производный экземпляр этого класса следующим образом:

var validationResult = _validator.Validate(request, ruleSet: "handler");

Как можно Я высмеиваю этот конкретный вызов Validate в моих модульных тестах? Если бы я не использовал наборы правил, моя программа установки выглядела бы следующим образом:

_validator.Setup(x => x.Validate(It.IsAny<CreateRequest>()))
          .Returns(validationResult);

Следующий вызов недопустим, поскольку необязательные параметры не допускаются в дереве выражений:

_validator.Setup(x => x.Validate(
                It.IsAny<CreateRequest>(), 
                ruleSet: It.IsAny<string>()))
          .Returns(validationResult);

Теоретически я мог бы установить это так:

_validator.Setup(x => x.Validate(
                It.IsAny<CreateRequest>(), 
                (IValidatorSelector)null,
                It.IsAny<string>()))
           .Returns(validationResult);

Но тогда это приведет к:

System.NotSupportedException : Unsupported expression: x => x.Validate<CreateRequest>(It.IsAny<CreateRequest>(), null, It.IsAny<string>())
    Extension methods (here: DefaultValidatorExtensions.Validate) may not be used in setup / verification expressions.

За исключением использования реального валидатора, которого я хочу избежать, как можно Я решил это и настроил Moq подходящим способом?

Ответы [ 2 ]

3 голосов
/ 16 марта 2020

Здесь действительно два вопроса.

  1. Во-первых, как имитировать необязательные параметры - просто обрабатывать необязательные параметры не обязательно.

  2. Однако вы пытаетесь имитировать метод расширения, который не возможен. Вместо этого вам нужно смоделировать метод, который расширение пытается вызвать. Беглый взгляд на источник, и я думаю, что под капотом он вызывает validator.Validate(ValidationContext), поэтому ваш код Moq может выглядеть примерно так:

    _validator
        .Setup(x => x.Validate(It.IsAny<ValidationContext<CreateRequest>>())
        .Returns(validationResult);
    
0 голосов
/ 16 марта 2020

Попробуйте

var mock = new Mock<AbstractValidator<object>>();
mock.Setup(x => x.Validate(It.Is<ValidationContext<object>>(ctx => IsExpectedRuleSet(ctx, new[] { "Rule1", "Rule2" }))))
    .Return(...);

mock.Object.Validate(new object(), ruleSet: "Rule1,Rule2");

bool IsExpectedRuleSet(ValidationContext context, string[] expectedRuleSet)
{
    return (context.Selector as FluentValidation.Internal.RulesetValidatorSelector)?.RuleSets.SequenceEqual(expectedRuleSet) == true;
}
...