Статьи

Как написать модульные тесты для .NET Core приложения

Написание модульных тестов — хорошая практика разработки программного обеспечения. В этой статье мы узнаем, как создать приложение C # .NET Core, придерживаясь подхода Test Driven Development (TDD). В подходе TDD перед реализацией функциональности вы пишете для нее модульный тест. Например, если вы хотите написать функцию для добавления двух чисел, сначала вы напишите проваленный модульный тест, а затем реализуете функциональность для прохождения теста.

В этом посте мы создадим приложение калькулятора. Для начала, давайте следовать структуре папок, как показано ниже:

  • CalculatorApp — Решение
  • CalculatorApp.Services — Проект приложения
  • CalculatorApp.Services.Tests — Тестовый проект

Вы можете использовать Visual Studio для создания проектов; однако в этом посте я буду использовать команды .NET Core для создания своих проектов, добавления тестов и запуска тестов. Вы также можете использовать MSTest или NUnit для написания модульных тестов, но в этом примере я буду использовать xUnit и dotnet test для написания и запуска своих модульных тестов.

Давайте начнем с открытия командной оболочки и продолжим: 

 Создание проекта приложения

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

Внутри каталога CalculatorApp мы собираемся создать новое решение, выполнив следующую команду:

 dotnet new sln 

После успешного выполнения команды вы должны получить сообщение «Файл решения шаблона создан успешно». Также внутри каталога CalculatorApp вы найдете файл с именем calculatorapp.sln.

Затем создайте каталог с именем CalculatorApp.Services. В этом каталоге будут храниться исходные коды приложения, т.е. все классы приложения калькулятора. Перейдите в каталог Calculatorapp.Services и создайте библиотеку классов, выполнив следующую команду:

 dotnet new classlib 

После успешного выполнения этой команды вы должны получить сообщение «Библиотека классов шаблонов создана успешно». Вы также найдете файл с именем calculatorapp.services.csproj в каталоге CalculatorApp.Services. Затем вам нужно добавить этот проект библиотеки классов в решение calculatorapp. Для этого вернитесь обратно в каталог calculatorapp и выполните команду:

 dotnet sln add .\calculatorapp.services\calculatorapp.services.csproj 

После успешного выполнения команды вы должны получить сообщение «Проект добавлен в решение».

Внутри папки CalculatorApp.Services вы найдете класс Class1 — переименуйте его в Calculator и измените класс, как показано в листинге ниже: 

Calculator.cs

using System;

namespace calculatorapp.services
{
    public class Calculator
    {

        public int Add(int num1, int num2)
        {
            throw new NotImplementedException();
        }

        public int Sub(int num1, int num2)
        {
            throw new NotImplementedException();

        }
    }
}

В приведенном выше листинге вы заметите, что функции Add и Sub не реализованы. Сначала мы напишем модульный тест, а затем реализуем эти функции.  

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

Чтобы добавить тестовые проекты, создайте каталог с именем CalculatorApp.Services.Tests и перейдите в каталог. В этом каталоге мы создадим проект MS Test, выполнив следующую команду:

 dotnet new mstest 

Эта команда создает тестовый проект, который использует MS Test в качестве тестовой библиотеки. После создания тестового проекта добавьте библиотеку исходного проекта в тестовый проект. Для этого выполните команду:

 dotnet add reference ../CalculatorApp.Services/CalculatorApp.Services.csproj 

 Эта  команда добавит ссылку на проект CalculatorAppService в тестовый проект. После добавления ссылки добавьте тестовый проект в решение, перейдя в корневой каталог calculatorapp и выполните команду:

 dotnet sln add .\CalculatorAppServices.tests\CalculatorAppServices.Tests.csproj 

Эта команда добавит тестовый проект в решение. После успешного выполнения команды вы должны получить сообщение «Проект добавлен в решение». 

Написание юнит-тестов

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

В тестовом проекте я переименовал файл UnitTest1.cs в Calculator.Test.cs, а имя класса в CalculatorTest. В конструкторе CalculatorTest нам нужно создать объект класса Calculator. Это можно сделать, как показано в листинге ниже: 

Calculator.Test.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using calculatorapp.services;
namespace CalculatorApp.Services.Tests
{
    [TestClass]
    public class CalculatorTest
    {

        Calculator _calc;

        public CalculatorTest()
        {
            _calc = new Calculator();
        }
    }
}

Модульный тест для добавления функции 

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

[TestMethod]
       public void shouldaddtwonumbers()
       {
           int res = _calc.Add(5, 3);
           Assert.AreEqual(res, 8);
       }

Для запуска теста перейдите в каталог CalculatorApp.Services.Tests и выполните команду:

dotnet test

Вы получите вывод «test fail», потому что функция Add не реализована, как показано на рисунке ниже:

Чтобы пройти тест, реализуйте функцию Add в классе Calculator, как показано в листинге ниже:

public int Add(int num1, int num2)
       {

           int result = num1 + num2;
           return result;
       }

Чтобы запустить тест сейчас, перейдите к директору CalculatorApp.Services.Tests и выполните команду:

 dotnet test 

В качестве вывода вы получите сообщение «тест пройден», как показано на рисунке ниже:

Теперь вы реализовали функцию добавления, придерживаясь подхода TDD в приложении .NET Core!

Модульный тест для подфункции

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

[TestMethod]
    public void shouldsubstracttwonumbers()
    {
        int res = _calc.Sub(5, 3);
        Assert.AreEqual(res, 2);
    }

Для запуска теста перейдите в каталог CalculatorApp.Services.Tests и выполните команду:

 dotnet test

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

Чтобы пройти тест, внедрите функцию Sub в классе Calculator, как показано в листинге ниже:

public int Sub(int num1, int num2)
{
    int result = num1 - num2;
    return result;

}

Теперь снова запустите тест, перейдя в каталог CalculatorApp.Services.Tests и выполнив:

 dotnet test

Теперь вы увидите, что оба теста пройдены, как показано здесь:

Теперь вы реализовали Sub-функциональность, придерживаясь подхода TDD в приложении .NET Core.

Завершение

До сих пор в этом посте мы создали приложение .NET Core Calculator, придерживаясь подхода TDD. Для создания тестов мы использовали тесты XUnit и dotnet. Для справки, вот исходный код класса Calculator и его тестового класса:

Calculator.cs

using System;

namespace calculatorapp.services
{
    public class Calculator
    {

        public int Add(int num1, int num2)
        {

            int result = num1 + num2;
            return result;
        }

        public int Sub(int num1, int num2)
        {
            int result = num1 - num2;
            return result;

        }
    }
}

Calculator.test.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using calculatorapp.services;
namespace CalculatorApp.Services.Tests
{
    [TestClass]
    public class CalculatorTest
    {

        Calculator _calc;

        public CalculatorTest()
        {
            _calc = new Calculator();
        }

        [TestMethod]
        public void shouldaddtwonumbers()
        {
            int res = _calc.Add(5, 3);
            Assert.AreEqual(res, 8);
        }

        [TestMethod]
        public void shouldsubstracttwonumbers()
        {
            int res = _calc.Sub(5, 3);
            Assert.AreEqual(res, 2);
        }


    }
}

И вот как вы пишете модульные тесты, а затем реализуете их функциональные возможности. Я надеюсь, что этот пост поможет вам начать писать модульные тесты для вашего следующего приложения .NET Core!