xUnit: Fact, Theory, fixtures, параллелизм

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

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

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

Спрашивают, как устроены жизненный цикл теста и общие фикстуры, и почему тесты в одном классе не идут параллельно.

Объяснение

xUnit — основной фреймворк для тестов на .NET. Для каждого тестового метода создаётся новый экземпляр класса, поэтому конструктор играет роль setup, а IDisposable.Dispose — teardown.

АтрибутНазначение
[Fact]обычный тест без параметров
[Theory] + [InlineData]параметризованный тест
[MemberData], [ClassData]данные из свойства или класса
IClassFixture<T>общий контекст на все тесты класса
ICollectionFixture<T> + [Collection]общий контекст на несколько классов
IAsyncLifetimeасинхронные setup/teardown
[Trait("cat","slow")]категории для фильтрации
public class PriceTests
{
    [Theory]
    [InlineData(100, 0.1, 90)]
    [InlineData(200, 0.25, 150)]
    public void Applies_discount(decimal price, decimal rate, decimal expected)
        => Assert.Equal(expected, Pricing.Discount(price, rate));
}

Фикстуры

public class DbFixture : IAsyncLifetime
{
    public string ConnectionString { get; private set; } = "";
    public async Task InitializeAsync() { /* поднять контейнер */ }
    public async Task DisposeAsync() { /* остановить */ }
}
 
public class RepoTests : IClassFixture<DbFixture>
{
    private readonly DbFixture _db;
    public RepoTests(DbFixture db) => _db = db;
}

Параллелизм

Тестовые классы (коллекции) выполняются параллельно, тесты внутри класса — последовательно. Общее состояние между классами нужно изолировать либо объединить классы в одну [Collection].

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

  • Статическое состояние делает тесты зависимыми и ломается при параллельном запуске.
  • async void в тестах недопустим: используйте async Task.
  • Не полагайтесь на порядок выполнения тестов.
  • Выводите диагностику через ITestOutputHelper, а не Console.
  • Для тестов на исключения: await Assert.ThrowsAsync<T>(() => ...).

Практика

  1. Превратите три похожих [Fact] в один [Theory].
  2. Сделайте IClassFixture с общей БД и очисткой данных между тестами.
  3. Отключите параллелизм для одной коллекции и проверьте, что состояние не «протекает».

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

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