← Назад к вопросам

Что использовал для Assert?

1.6 Junior🔥 241 комментариев
#Тестирование

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Методы и библиотеки для Assert в C#

Я использовал встроенные механизмы фреймворков для модульного тестирования, а также специализированные библиотеки для различных сценариев валидации. Вот основные инструменты, которые применял в своей практике:

1. Встроенные Assert-методы NUnit/xUnit

NUnit предоставляет классический набор методов через класс Assert:

// Базовые проверки
Assert.AreEqual(expected, actual);
Assert.IsTrue(condition);
Assert.IsNull(obj);
Assert.IsInstanceOf<MyType>(obj);

// Коллекции
CollectionAssert.AreEqual(expectedList, actualList);
CollectionAssert.Contains(collection, item);

// Исключения
Assert.Throws<InvalidOperationException>(() => method());

xUnit использует более лаконичный подход:

// В xUnit нет статического класса Assert
Assert.Equal(expected, actual);
Assert.True(condition);
Assert.Null(obj);
Assert.IsType<MyType>(obj);

// Проверка исключений
var exception = Assert.Throws<InvalidOperationException>(() => method());
Assert.Equal("Expected message", exception.Message);

2. Fluent Assertions - основная библиотека

Для читаемых и выразительных проверок активно использую FluentAssertions:

// Более читаемый синтаксис
actual.Should().Be(expected);
condition.Should().BeTrue();
obj.Should().BeNull();
obj.Should().BeOfType<MyType>();

// Цепочки проверок
result.Should()
    .NotBeNull()
    .And.HaveCount(5)
    .And.Contain(item => item.Id > 0);

// Строки
text.Should()
    .StartWith("Hello")
    .And.EndWith("World")
    .And.Contain("test");

// Исключения
action.Should()
    .Throw<InvalidOperationException>()
    .WithMessage("Expected message*")
    .Where(ex => ex.ErrorCode == 100);

// Коллекции
collection.Should()
    .HaveCount(3)
    .And.ContainSingle(x => x.IsActive)
    .And.OnlyHaveUniqueItems();

3. Специализированные проверки

Для разных типов данных применяю соответствующие методы:

// Даты и время
dateTime.Should().BeCloseTo(expected, TimeSpan.FromSeconds(1));

// Числа с точностью
number.Should().BeApproximately(3.14, 0.01);

// События
monitor.Should().Raise("EventName")
    .WithArgs<EventArgs>(args => args.IsValid);

// JSON
jsonString.Should().BeEquivalentTo(expectedJson);

4. Пользовательские Assert-методы

Создаю кастомные методы проверки для доменных объектов:

public static class CustomAssertions
{
    public static void ShouldBeValidOrder(this Order order)
    {
        order.Should().NotBeNull();
        order.Id.Should().BePositive();
        order.Items.Should().NotBeEmpty();
        order.TotalAmount.Should().BeGreaterThan(0);
        
        // Бизнес-правила
        if (order.Type == OrderType.Express)
        {
            order.DeliveryDate.Should().BeWithin(3).Days();
        }
    }
    
    public static void ShouldContainError(this ValidationResult result, string code)
    {
        result.Errors.Should()
            .Contain(e => e.Code == code, 
                $"ожидалась ошибка с кодом '{code}'");
    }
}

5. Assert для асинхронного кода

Для тестирования асинхронных операций:

// Асинхронные проверки
await asyncMethod.Should().NotThrowAsync();
var result = await asyncMethod.Should().CompleteWithinAsync(TimeSpan.FromSeconds(5));

// Асинхронные исключения
await asyncAction.Should()
    .ThrowAsync<HttpException>()
    .Where(ex => ex.StatusCode == 404);

6. Дополнительные библиотеки

В зависимости от контекста использую:

  • AutoFixture.AutoNSubstitute для создания mock-объектов с автоматической настройкой
  • Moq или NSubstitute для проверки взаимодействий (Assert на вызовы методов)
  • Bogus для генерации тестовых данных с последующей проверкой
  • Snapshot testing (Snapshooter) для сравнения сложных объектов

7. Best Practices

Из своего опыта выделяю следующие принципы:

  1. Читаемость превыше всего - тесты должны быть понятны даже не-разработчикам
  2. Конкретные сообщения об ошибках - всегда добавляю поясняющие сообщения
  3. Одна проверка на тест - каждый тест проверяет одну конкретную вещь
  4. Использование правильных матчеров - например, BeEquivalentTo вместо поэлементного сравнения для объектов
  5. Проверка не только happy path - обязательно тестирую граничные случаи и ошибки

Пример комплексного использования:

[Test]
public async Task ProcessOrder_ValidRequest_ReturnsSuccess()
{
    // Arrange
    var order = new OrderBuilder().WithItems(3).Build();
    var service = new OrderService();
    
    // Act
    var result = await service.ProcessOrderAsync(order);
    
    // Assert
    result.Should().NotBeNull();
    result.Status.Should().Be(OrderStatus.Processed);
    result.ProcessedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
    result.Total.Should().Be(order.Items.Sum(i => i.Price * i.Quantity));
    
    // Проверка side effects
    _loggerMock.Verify(x => x.LogInfo("Order processed"), Times.Once);
    _repositoryMock.Verify(x => x.SaveAsync(It.IsAny<Order>()), Times.Once);
}

Ключевой вывод: выбор инструментов Assert зависит от контекста - для простых unit-тестов достаточно встроенных методов, для сложных интеграционных тестов и требующих высокой читаемости лучше использовать Fluent Assertions в комбинации со специализированными библиотеками.