FluentAssertions и AutoFixture

↑ 2.4 Тестирование в .NET — основы · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Меньший приоритет, но показывает опыт: как сделать проверки читаемыми и не писать вручную длинные тестовые данные.

Объяснение

FluentAssertions (и Shouldly)

Читаемые проверки с осмысленными сообщениями при падении.

result.Should().NotBeNull();
result.Items.Should().HaveCount(3).And.OnlyContain(i => i.Price > 0);
order.Should().BeEquivalentTo(expected, o => o.Excluding(x => x.CreatedAt));
 
await FluentActions.Awaiting(() => sut.PayAsync(order))
    .Should().ThrowAsync<PaymentException>().WithMessage("*declined*");

BeEquivalentTo сравнивает объекты структурно, что удобно для DTO и графов.

Лицензия

Начиная с 8-й версии FluentAssertions распространяется по коммерческой лицензии для коммерческого использования. Альтернативы: Shouldly, AwesomeAssertions (форк версии 7).

AutoFixture

Генерирует значения для тестовых данных, чтобы не заполнять вручную ненужные поля.

var fixture = new Fixture();
var order = fixture.Build<Order>()
    .With(o => o.Status, OrderStatus.New)
    .Create();
 
var items = fixture.CreateMany<OrderItem>(5).ToList();

С AutoFixture.Xunit2: [Theory, AutoData] void Test(Order order). С AutoMoq/AutoNSubstitute фикстура ещё и подставляет зависимости SUT.

Builder как альтернатива

var order = new OrderBuilder().WithItems(3).Paid().Build();

Явные builder-ы делают тест понятным: видно только значимые для сценария поля.

Нюансы и подводные камни

  • Случайные данные усложняют воспроизведение: логируйте seed или фиксируйте значимые поля явно.
  • BeEquivalentTo может «проглатывать» несовпадение, если конфигурация слишком мягкая.
  • Слишком много магии AutoFixture скрывает суть теста.
  • Тест должен показывать, что важно: важные значения задавайте явно, остальное генерируйте.

Практика

  1. Перепишите три теста, заменив Assert.Equal на fluent-проверки и сравните сообщения об ошибках.
  2. Сгенерируйте 100 заказов через AutoFixture и проверьте инвариант.
  3. Напишите builder для сложной сущности.

Вопросы с ответами

Связанные темы