Тестирование C# для начинающих: с чего начать в 2024

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему тестирование C# — это не страшно, а выгодно?

Если вы только начинаете свой путь в C# и слышали, что «хороший разработчик всегда пишет тесты», но понятия не имеете, с какой стороны подойти к этому зверю — вы попали по адресу. Тестирование кода часто пугает новичков: кажется, что это что-то сложное, требующее глубоких знаний архитектуры и тонн настроек. На самом деле, написание тестов на C# — это навык, который можно освоить за один вечер, а польза от него будет длиться годами.

Представьте, что вы собрали сложный механизм из тысяч деталей. Вы же не будете включать его на полную мощность без проверки каждого узла? Так и с программой: unit-тестирование C# позволяет проверить каждый «винтик» вашего кода отдельно, не дожидаясь, пока вся система рухнет в production. В этой статье мы разберем тестирование C# с нуля: от выбора фреймворка до написания первого осмысленного теста. Поехали!

С чего начать тестирование на C#: подготовка окружения

Прежде чем писать код, давайте убедимся, что у вас есть всё необходимое. Для тестирования C# вам понадобится:

  • Visual Studio 2022 (Community edition — бесплатно) или JetBrains Rider (если есть лицензия).
  • .NET SDK (версия 6, 7 или 8 — подойдет любая LTS).
  • Базовое понимание ООП в C#: классы, методы, интерфейсы.

Когда среда готова, создайте новый проект. Я рекомендую сразу разделять код на два проекта: основной (ваша библиотека или приложение) и тестовый. В Visual Studio это делается командой: File → New → Project → xUnit Test Project (.NET Core) или NUnit Test Project. Но мы пойдем чуть дальше и разберем оба популярных инструмента.

Выбираем фреймворк: NUnit vs xUnit

В мире C# есть два главных «игрока» для написания модульных тестов: NUnit и xUnit. Оба отлично работают, но есть нюансы:

  • NUnit — классика, пришедшая из Java (аналог JUnit). Имеет атрибуты [Test], [SetUp], [TearDown]. Очень нагляден для новичков.
  • xUnit — современный фреймворк от создателей ASP.NET. Использует [Fact] и [Theory]. Считается более «чистым» и лучше интегрируется с .NET Core.

Для начинающих я советую xUnit — он проще, не требует лишних атрибутов, и его легче понять. Но если в вашей команде используют NUnit — не беда, мы рассмотрим оба варианта.

Первый юнит-тест на C#: пишем код

Допустим, у нас есть простой класс-калькулятор:

public class Calculator
{
    public int Add(int a, int b) => a + b;
    
    public int Divide(int a, int b)
    {
        if (b == 0)
            throw new DivideByZeroException("На ноль делить нельзя!");
        return a / b;
    }
}

Теперь напишем тесты для этого класса. Создадим тестовый проект (xUnit) и добавим ссылку на основной проект.

Пример теста с xUnit

using Xunit;

public class CalculatorTests
{
    [Fact]
    public void Add_ShouldReturnSum_WhenTwoNumbers()
    {
        // Arrange
        var calculator = new Calculator();
        
        // Act
        var result = calculator.Add(3, 5);
        
        // Assert
        Assert.Equal(8, result);
    }
    
    [Fact]
    public void Divide_ShouldThrowException_WhenDivideByZero()
    {
        var calculator = new Calculator();
        
        Assert.Throws<DivideByZeroException>(() => calculator.Divide(10, 0));
    }
}

Обратите внимание на структуру Arrange-Act-Assert (AAA). Это золотой стандарт написания тестов: сначала готовим данные, потом выполняем действие, затем проверяем результат. Запомните этот паттерн — он спасет вас от хаоса в тестах.

Пример теста с NUnit

Для сравнения — тот же тест на NUnit:

using NUnit.Framework;

[TestFixture]
public class CalculatorTests
{
    private Calculator _calculator;
    
    [SetUp]
    public void Setup()
    {
        _calculator = new Calculator();
    }
    
    [Test]
    public void Add_ShouldReturnSum_WhenTwoNumbers()
    {
        var result = _calculator.Add(3, 5);
        Assert.AreEqual(8, result);
    }
    
    [Test]
    public void Divide_ShouldThrowException_WhenDivideByZero()
    {
        Assert.Throws<DivideByZeroException>(() => _calculator.Divide(10, 0));
    }
}

Как видите, разница в синтаксисе минимальна, но NUnit требует больше «ритуальных» атрибутов. xUnit выглядит чище.

Тестирование с моками: Moq для начинающих

В реальных проектах ваш код почти всегда зависит от внешних сервисов: базы данных, API, файловой системы. Тестировать такие зависимости напрямую — плохая практика. Вместо этого используют mock-объекты. Самый популярный инструмент для этого в C# — Moq.

Представьте, что у нас есть сервис, который отправляет email:

public interface IEmailService
{
    void Send(string to, string subject, string body);
}

public class NotificationService
{
    private readonly IEmailService _emailService;
    
    public NotificationService(IEmailService emailService)
    {
        _emailService = emailService;
    }
    
    public void NotifyUser(string email)
    {
        _emailService.Send(email, "Привет!", "Добро пожаловать в систему.");
    }
}

Как протестировать NotifyUser, не отправляя реальные письма? Очень просто — используем Moq:

using Moq;
using Xunit;

public class NotificationServiceTests
{
    [Fact]
    public void NotifyUser_ShouldCallSend_WithCorrectParameters()
    {
        // Arrange
        var mockEmailService = new Mock<IEmailService>();
        var service = new NotificationService(mockEmailService.Object);
        
        // Act
        service.NotifyUser("test@example.com");
        
        // Assert
        mockEmailService.Verify(
            e => e.Send("test@example.com", "Привет!", "Добро пожаловать в систему."),
            Times.Once);
    }
}

Обратите внимание: мы не создаем реальный email-сервис. Мы создаем его «заглушку» (mock) и проверяем, что метод Send был вызван с правильными аргументами. Это основа mocking C# — вы тестируете логику вашего кода, а не внешние системы.

Параметризованные тесты: меньше кода — больше покрытия

Часто нужно проверить одну и ту же логику с разными входными данными. Писать для каждого случая отдельный тест — скучно и

Блоги

Рекомендаций по книгам