Какие фреймворки и подходы к unit-тестированию вы знаете в .NET?

«Какие фреймворки и подходы к unit-тестированию вы знаете в .NET?» — вопрос из категории Тестирование, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В экосистеме .NET unit-тестирование — стандартная практика. Выбор фреймворка и инструментов зависит от предпочтений команды и требований проекта.

Популярные фреймворки для тестирования:

  1. xUnit.net

    • Особенности: В настоящее время считается де-факто стандартом для новых проектов. Чистый дизайн, отсутствие атрибутов [SetUp]/[TearDown] (используется конструктор класса и IDisposable), поддержка параллельного запуска тестов "из коробки".
    • Пример:

      public class CalculatorTests : IDisposable
      {
          private readonly Calculator _sut; // System Under Test
      
          public CalculatorTests() // Аналог [SetUp]
          {
              _sut = new Calculator();
          }
      
          [Fact]
          public void Add_TwoPositiveNumbers_ReturnsCorrectSum()
          {
              // Arrange
              int a = 5, b = 3;
              // Act
              var result = _sut.Add(a, b);
              // Assert
              Assert.Equal(8, result);
          }
      
          [Theory]
          [InlineData(1, 2, 3)]
          [InlineData(-5, 5, 0)]
          public void Add_VariousInputs_ReturnsCorrectSum(int a, int b, int expected)
          {
              var result = _sut.Add(a, b);
              Assert.Equal(expected, result);
          }
      
          public void Dispose() // Аналог [TearDown]
          {
              _sut?.Dispose();
          }
      }
  2. NUnit

    • Особенности: Один из старейших и самых зрелых фреймворков. Богатый набор атрибутов ([SetUp], [TearDown], [TestCase]). Широко используется в legacy-проектах.
    • Пример:

      [TestFixture]
      public class StringTests
      {
          [SetUp]
          public void Setup() { ... }
      
          [Test]
          [TestCase("abc", "ABC")]
          public void ToUpper_ValidString_ReturnsUppercase(string input, string expected)
          {
              Assert.That(input.ToUpper(), Is.EqualTo(expected));
          }
      }
  3. MSTest (Microsoft.VisualStudio.TestTools.UnitTesting)

    • Особенности: Тесно интегрирован с Visual Studio. Прост в освоении, но менее гибок, чем xUnit или NUnit. Постоянно развивается.

Ключевые вспомогательные библиотеки:

  • Moq / NSubstitute: Библиотеки для создания моков (test doubles). Позволяют изолировать тестируемый код от его зависимостей.

    // Пример с Moq
    var mockLogger = new Mock<ILogger>();
    mockLogger.Setup(log => log.Write(It.IsAny<string>())).Verifiable();
    
    var service = new OrderService(mockLogger.Object);
    service.ProcessOrder(testOrder);
    
    mockLogger.Verify(); // Проверяем, что метод Write был вызван
  • FluentAssertions / Shouldly: Библиотеки для более читаемых утверждений (assertions).

    // FluentAssertions
    result.Should().Be(42);
    collection.Should().ContainSingle().Which.Name.Should().Be("John");
  • AutoFixture: Для автоматического создания тестовых данных, избавляет от ручного создания объектов в секции Arrange.

Общие лучшие практики:

  • Изоляция: Тест не должен зависеть от внешних систем (БД, файлы, API). Используйте моки.
  • Соглашение об именовании: MethodUnderTest_Scenario_ExpectedBehavior (например, ProcessOrder_EmptyCart_ThrowsException).
  • Один тест — одна логическая проверка.
  • Тесты должны быть быстрыми, повторяемыми и самодостаточными.