Модульное тестирование C# с TUnit и .NET

В этом руководстве вы познакомитесь с интерактивным процессом пошагового создания примерного решения, чтобы изучить концепции модульного тестирования.

В этой статье описывается тестирование проекта .NET Core. Если вы тестируете проект ASP.NET Core, см. тесты интеграции в ASP.NET Core.

Prerequisites

  • .NET SDK 10 или более поздних версий.
  • Текстовый редактор или редактор кода по вашему выбору.

TUnit полностью построен на Microsoft. Testing.Platform (MTP) и не поддерживает VSTest. В этом руководстве используется режим dotnet testMTP, для которого требуется пакет SDK .NET 10.

Создание исходного проекта

Откройте окно терминала. Создайте каталог с именем unit-testing-using-tunit для хранения решения. В этом новом каталоге выполните следующую команду, чтобы создать новый файл решения для библиотеки классов и тестового проекта:

dotnet new sln

Затем создайте каталог PrimeService . На следующей схеме показаны структура каталога и файлов на данный момент:

/unit-testing-using-tunit
    unit-testing-using-tunit.slnx
    /PrimeService

Сделайте PrimeService текущим каталогом и выполните следующую команду, чтобы создать исходный проект:

dotnet new classlib

Переименуйте Class1.cs в PrimeService.cs. Вы создаете неудачную реализацию класса PrimeService:

using System;

namespace Prime.Services
{
    public class PrimeService
    {
        public bool IsPrime(int candidate)
        {
            throw new NotImplementedException("Please create a test first.");
        }
    }
}

Измените каталог обратно на каталог unit-testing-using-tunit . Выполните следующую команду, чтобы добавить проект библиотеки классов в решение:

dotnet sln add PrimeService/PrimeService.csproj

Создание тестового проекта

Затем создайте каталог PrimeService.Tests. В следующей схеме показана структура каталога:

/unit-testing-using-tunit
    unit-testing-using-tunit.slnx
    /PrimeService
        Source Files
        PrimeService.csproj
    /PrimeService.Tests

Шаблоны проектов TUnit не включены в пакет SDK .NET. Установите их с помощью следующей команды:

dotnet new install TUnit.Templates

Измените каталог на каталог PrimeService.Tests и создайте проект с помощью следующей команды:

dotnet new TUnit

Note

Короткие имена шаблонов чувствительны к регистру. Используйте TUnit, а не tunit.

Команда dotnet new создает тестовый проект, использующий TUnit в качестве тестовой библиотеки. Созданный файл PrimeService.Tests.csproj — это исполняемый проект, ссылающийся на пакет TUnit (номер версии может отличаться):

<PropertyGroup>
  <ImplicitUsings>enable</ImplicitUsings>
  <Nullable>enable</Nullable>
  <OutputType>Exe</OutputType>
  <TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="TUnit" Version="1.*" />
</ItemGroup>

Пакет TUnit включает платформу тестирования, библиотеку утверждений и средство выполнения тестов MTP, поэтому проект не нуждается в других пакетах тестирования. Шаблон также добавляет примеры тестов. Удалите все файлы .cs и каталог Data из каталога PrimeService.Tests, так как это руководство заменяет их собственными тестами.

Теперь добавьте библиотеку классов PrimeService в качестве другой зависимости в проект. Используйте команду dotnet reference add:

dotnet reference add ../PrimeService/PrimeService.csproj

В следующей схеме показан окончательный макет решения:

/unit-testing-using-tunit
    unit-testing-using-tunit.slnx
    /PrimeService
        Source Files
        PrimeService.csproj
    /PrimeService.Tests
        Test Source Files
        PrimeService.Tests.csproj

Выполните следующую команду в каталоге unit-testing-using-tunit :

dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj

Настройка режима MTP для dotnet test

Так как TUnit не поддерживает VSTest, dotnet test должен выполняться в режиме MTP. В каталоге unit-testing-using-tunit создайте файл global.json со следующим содержимым:

{
    "test": {
        "runner": "Microsoft.Testing.Platform"
    }
}

Дополнительные сведения см. в режиме MTP dotnet test.

Создание первого теста

Вы пишете провальный тест, добиваетесь его прохождения, а затем повторяете процесс. В каталоге PrimeService.Tests создайте файл PrimeService_IsPrimeShould.cs со следующим кодом:

namespace Prime.UnitTests.Services
{
    using Prime.Services;

    public class PrimeService_IsPrimeShould
    {
        private readonly PrimeService _primeService = new();

        [Test]
        public async Task IsPrime_InputIs1_ReturnFalse()
        {
            var result = _primeService.IsPrime(1);

            await Assert.That(result).IsFalse();
        }
    }
}

Атрибут [Test] указывает, что метод является методом тестирования. TUnit не нуждается в атрибуте у класса. Утверждения TUnit являются асинхронными, поэтому метод теста возвращает Task и ожидает Assert.That. Пакет TUnit добавляет глобальные using директивы для своих пространств имен, поэтому файл не нуждается в них.

Note

Директива using Prime.Services; находится внутри пространства имен намеренно. MTP создает точку входа тестового приложения в корневом пространстве имен проекта, PrimeService.Tests. Это пространство имен скрывает класс PrimeService от директивы using в верхней части файла, но не от директивы внутри пространства имен.

Сохраните этот файл и выполните dotnet test команду, чтобы создать тесты и библиотеку классов и запустить тесты. Тестовый проект TUnit содержит точку входа программы для выполнения тестов. dotnet test позволяет запустить тестовое приложение с помощью созданного проекта модульных тестов.

Ваш тест не удался. Вы еще не создали реализацию. Сделайте тестовый проход, написав самый простой код в PrimeService классе, который работает:

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Please create a test first.");
}

В каталоге unit-testing-using-tunit запустите dotnet test еще раз. Команда dotnet test запускает сборку для проекта PrimeService, а затем для проекта PrimeService.Tests. После сборки обоих проектов он запускает этот одиночный тест. Это пройдет.

Добавление дополнительных функций

Теперь, когда вы сделали один тестовый проход, пришло время написать больше. Существует несколько других простых случаев для простых чисел: 0, -1. Вы можете добавить новые тесты с атрибутом [Test], но это быстро становится утомительным. TUnit предоставляет атрибут [Arguments] для создания набора тестов, предназначенных для выполнения одного и того же кода, но с разными входными аргументами.

Вместо создания новых тестов примените этот атрибут для создания одного теста на основе данных. Замените метод IsPrime_InputIs1_ReturnFalse следующим кодом. Тест на основе данных — это метод, который проверяет несколько значений меньше двух значений, что является самым низким прайм-числом:

[Test]
[Arguments(-1)]
[Arguments(0)]
[Arguments(1)]
public async Task IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
    var result = _primeService.IsPrime(value);

    await Assert.That(result).IsFalse();
}

Запустите dotnet test, и два из этих тестов завершаются с ошибкой. Чтобы выполнить все тесты, измените предложение if в начале метода IsPrime в файле PrimeService.cs:

if (candidate < 2)

Продолжайте итерацию, добавляя дополнительные тесты и код в основную библиотеку.

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

См. также