Тестирование FluentValidation ChildRules - PullRequest
1 голос
/ 28 февраля 2020

Учитывая следующий объект:

public class PatchDTO
{
    public PatchDTO()
    {
        Data = new List<Datum>();
    }
    public List<Datum> Data { get; set; }

    public class Datum
    {
        public Datum()
        {
            Attributes = new Dictionary<string, object>();
        }
        public string Id { get; set; }
        public Dictionary<string, object> Attributes { get; set; }
    }
}

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

RuleFor(oo => oo.Data)
    .NotEmpty()
    .WithMessage("One or more Data blocks must be provided");

RuleForEach(d => d.Data).ChildRules(datum =>
{
    datum.RuleFor(d => d.Id)
        .NotEmpty()
        .WithMessage("Invalid 'Data.Id' value");
});

Который я пытаюсь протестировать, используя расширения теста как таковые:

[Theory]
[InlineData(null)]
[InlineData("")]
public void Id_Failure(string id)
{
    dto.Data[0].Id = id;
    var result = validator.TestValidate(dto);
    result.ShouldHaveValidationErrorFor(oo => oo.Data[0].Id)
        .WithErrorMessage("Invalid 'Data.Id' value");
}

Но когда я запускаю тест, он говорит:

FluentValidation.TestHelper.ValidationTestException
  HResult=0x80131500
  Message=Expected a validation error for property Id
----
Properties with Validation Errors:
[0]: Data[0].Id

Но, как вы можете видеть в разделе «Ошибки валидации», он фактически обнаружил ошибку проверки, но не привязывая это к этому тесту. Итак, как мне проверить эти ChildRules или сообщить методу расширения теста, какое свойство он должен проверять?

(я также использовал validator.ShouldHaveValidationErrorFor напрямую с теми же результатами)

1 Ответ

0 голосов
/ 29 февраля 2020

У меня раньше была эта проблема, и я прибегнул к использованию перегрузки строки для ShouldHaveValidationErrorFor

Следующие тесты (nunit) прошли

[TestCase(null)]
[TestCase("")]
public void Id_InvalidValue_HasError(string id)
{
    var fixture = new Fixture();
    var datum = fixture.Build<PatchDTO.Datum>().With(x => x.Id, id).Create();
    var dto = fixture.Build<PatchDTO>().With(x => x.Data, new List<PatchDTO.Datum> { datum }).Create();

    var validator = new PatchDTOValidator();

    var validationResult = validator.TestValidate(dto);

    validationResult.ShouldHaveValidationErrorFor("Data[0].Id")
        .WithErrorMessage("Invalid 'Data.Id' value");
}

Прошло много времени с тех пор, как я посмотрел в этом, но я полагаю, что проблема в расширении ShouldHaveValidationErrorFor, совпадающем по имени свойства, и перегрузка выражения свойства не разрешает имя свойства в 'Data [0] .Id'. Если вы проверите результаты проверки, вы получите объект ValidationError, который выглядит примерно так:

{
   "PropertyName":"Data[0].Id",
   "ErrorMessage":"Invalid 'Data.Id' value",
   "AttemptedValue":"",
   "CustomState":null,
   "Severity":0,
   "ErrorCode":"NotEmptyValidator",
   "FormattedMessageArguments":[

   ],
   "FormattedMessagePlaceholderValues":{
      "PropertyName":"Id",
      "PropertyValue":""
   },
   "ResourceName":null
}

EDIT:

Быстро взглянул на перегрузку выражения свойства, как показано ниже

public IEnumerable<ValidationFailure> ShouldHaveValidationErrorFor<TProperty>(Expression<Func<T, TProperty>> memberAccessor)
{
  return ValidationTestExtension.ShouldHaveValidationError(this.Errors, ValidatorOptions.PropertyNameResolver(typeof (T), memberAccessor.GetMember<T, TProperty>(), (LambdaExpression) memberAccessor), true);
}

Предположительно, вы можете использовать другой / написать свой собственный обработчик имен свойств для обработки случая, так как он настраивается. Вам, вероятно, придется покопаться в выражении, чтобы сделать это.

...