Эксперт
Сергей
Сергей
Задать вопрос
Мы готовы помочь Вам.

Юнит-тестирование (англ. «unit-testing», или блочное тестирование) —
тестирование отдельного элемента изолированно от остальной системы.
Относительно парадигмы объектно-ориентированного программирования
системой является вся программа, а отдельным элементом — класс или его
метод. Юнит-тестирование предназначено для проверки правильности работы отдельно взятого класса. Чтобы исключить из результатов тестирования влияние потенциальных ошибок других классов, тестируемый класс
должен быть максимально изолирован, т. е. не использовать объекты и методы других классов. Данное требование в итоге позволяет иначе взглянуть на взаимодействие классов и выполнить рефакторинг на уменьшение
связности классов.
Фактически, юнит-тестирование заключается в написании некоторого класса-обёртки, который бы создавал экземпляр тестируемого класса. В
классе-обёртке создаются методы-тесты, выполняющие следующий алгоритм:
1. Создаются входные параметры — тестовые данные.
2. Подают тестовые данные на вход общедоступного (c модификатором доступа public в C#) метода тестируемого класса.
3. Сравнивают возвращаемое тестируемым методом значение с некоторым эталоном — заранее известным результатом, который должен получиться при правильной работе данного метода. Данный эталон определяется в ТЗ, спецификациях или другой проектной документации.
4. Если результат работы метода совпадает с эталоном — тест пройден. В любом другом случае тест считается провальным.
По данному алгоритму проверяется каждый общедоступный метод
тестируемого класса. Защищенные или закрытые члены класса тестированию не подвергаются, чтобы не нарушать инкапсуляцию класса.

Таким образом, юнит-тесты представляют программный код, который
также требует постоянной поддержки и следования определенным правилам
оформления. В отличие от других видов тестирования проведение юниттестирования — обязанность разработчиков, а не тестировщиков.
4.1 Задание на лабораторную работу
1. Скачать библиотеку Nunit с сайта nunit.org и установить.
2. Запустите ваше решение в Visual Studio и создайте в нём новый
проект — библиотеку классов UnitTests:
screenshot 4

Поскольку в данном проекте обычно хранятся блочные и интеграционные тесты всего решения, его внутренняя организация должна повторять
организацию решения. В нашем случае, внутри проекта необходимо создать отдельную папку для хранения тестов проекта Model.
3. Добавьте в проект ссылку на библиотеку Nunit для возможности
написания тестов в проекте. Данную ссылку можно подключить через
вкладку «Расширения» в окне «Менеджер ссылок»:
60
Рисунок 4.2 — Менеджер ссылок проекта в Visual Studio
Вам нужно подключить только «nunit.framework». Возможная вторая
ссылка на «nunit.mocks» в данной лабораторной не рассматривается, она
необходима для создания более сложных интеграционных тестов (см.
«Мок-тестирование», «Мок-объекты»).
4. Создайте внутри папки Model проекта UnitTests класс с именем
<ИмяТестируемогоКласса>Test.cs. В нашем примере для тестируемого
класса MyClass класс с тестами будет называться MyClassTest.
5. Рассмотрим написание блочных тестов на примере следующего
класса:
namespace Model
{
/// <summary>
/// Пример класса.
/// </summary>
public class MyClass
{
/// <summary>
/// Свойство, выражающее количество чего-нибудь.
/// </summary>
public int Count {get; set;}
/// <summary>
/// Выполнить деление двух вещественных чисел.
/// </summary>
/// <param name=”a”>Числитель.</param>
61
/// <param name=”b”>Знаменатель.</param>
/// <returns> Результат деления.</returns>
public double Divide(double a, double b)
{

}
}
}
Реализация класса опущена специально, в настоящий момент она не
важна. Важно, что в классе находятся два общедоступных члена с описанием их поведения. На основе этого мы можем придумать тестовые случаи, которые и будут проверяться юнит-тестированием.
6. В первую очередь, обозначим наш класс юнит-тестов как тестовый. Для этого перед объявлением класса добавим атрибут [TestFixture]:
using NUnit.Framework;
namespace UnitTests.Model
{
/// <summary>
/// Набор тестов для класса MyClass.
/// </summary>
[TestFixture]
public class MyClassTest
{
}
}
7. Далее сформируем метод, который будет выполнять тестирование
свойства Count. Тест будет заключаться в том, что мы создадим экземпляр
тестируемого класса и попытаемся в его свойство Count поместить как
корректные, так и некорректные значения. Для начала напишем сам метод:
using Model;
using NUnit.Framework;
namespace Model
{
/// <summary>
/// Набор тестов для класса MyClass.
/// </summary>
[TextFixture]
public class MyClassTest
{
62
/// <summary>
/// Тестирование свойства Count.
/// </summary>
/// <param name=”count”>Значение свойства Count.</param>
[Test]
public double CountTest(int count)
{
var myClass = new MyClass();
myClass.Count = count;
}
}
}
На вход метод принимает некоторое целочисленное значение, которое мы будем присваивать в свойство Count. Входные параметры тестового метода нужны нам для возможности создания нескольких тестовых случаев, проверяемых одним тестом.
8. Добавим некоторый тестовый случай, проверяющий работу свойства Count при обычном значении, например 4. Для этого добавим после
атрибута [Test] еще один атрибут [TestCase] с описанием входных данных
и названием тестового случая:
[Test]
[TestCase(4, TestName = «Тестирование Count при присваивании 4.»)]
public void CountTest(int count)
{
var myClass = new MyClass();
myClass.Count = count;
}
9. Запустим тест и проверим, выполняется ли он. Если у вас установлен Resharper, для запуска тестов достаточно нажать на специальный значок на панели слева:
63
Рисунок 4.3 — Пиктограммы для запуска юнит-тестов
Первый значок предназначен для запуска всех тестов, описанных в
данном классе. Второй значок предназначен для запуска конкретного тестового метода. При этом в контекстном меню можно указать, запустить все
тестовые случаи или только один конкретный. У нас пока только один тест
с одним тестовым случаем, его и запустим. При запуске тестов появится
следующая панель «Unit Test Sessions» (её можно найти во вкладке Resharper->Tools->Unit Test Sessions):
Рисунок 4.4 — Панель сессий тестирования
64
Данная панель показывает новую созданную сессию тестирования.
Каждая сессия может содержать свой набор проверяемых тестов:
• Иерархию тестов относительно проекта и класса.
• Успешное завершение нашего теста (отмечен зеленой галочкой и
статусом Passed).
У тестов внутри сессии возможны следующие статусы:
• Тест пройден.
• Тест провален — в результате будут показаны исходные данные,
ожидаемый и фактический результаты выполнения теста.
• Результат тестирования устарел — если были совершены изменения в тестируемом или тестирующем классах.
При запуске тестов выполняется компилирование тестируемого проекта и тестирующего проекта. Тесты не будут запущены, если при компилировании какого-либо из проектов возникла ошибка. Для запуска тестов
также необязательно делать проект UnitTests запускаемым проектом.
10. Добавим еще тестовых случаев для свойства Count. Одним из
способов формирования позитивных тестовых случаев является определение краевых условий. Например, мы знаем, что свойство Count хранит в
себе количество некоторых элементов. Это число может быть достаточно
большим, но обязательно положительным или 0. Соответственно, мы определили интервал от 0 до максимального значения int. На основе этого
предположения формируется 4 тестовых случая: минимально допустимое
значение, минимально допустимое значение плюс 1, максимально допустимое значение, максимально допустимое значение –1:
[TestCase(4, TestName = «Тестирование Count при присваивании 4.»)]
[TestCase(0, TestName = «Тестирование Count при присваивании 0.»)]
[TestCase(1, TestName = «Тестирование Count при присваивании 1.»)]
[TestCase(int.MaxValue, TestName = «Тестирование Count при присваивании MaxValue.»)]
[TestCase(int.MaxValue-1, TestName = «Тестирование Count при присваивании MaxValue-1.»)]
65
После запуска тестов мы убеждаемся, что свойство действительно
может принимать подобные значения.
Рисунок 4.5 — Запуск тест-кейсов для одного теста
11. Мы описали позитивные сценарии использования свойства
Count, т. е. мы присваивали такие значения, которые являются корректными для свойства Count. Однако куда более важно протестировать негативные сценарии — подача заведомо некорректных данных с ожиданием возникновения ошибки или исключения. Если программа не среагировала на
некорректные данные исключением — это ошибка, так как неправильные
входные данные для метода или свойства в итоге могут привести к неправильной работе других методов и классов, а отлаживать подобные отложенные ошибки достаточно трудоёмкий процесс. Поэтому:
• Программа, класс или метод должны реагировать на подачу некорректных данных исключением или любым другим способом
сообщения об ошибке.
• Юнит-тестирование должно проверять негативные сценарии для
классов и методов для избегания возникновения отложенных
ошибок.
Для свойства Count подобным негативным сценарием может быть
попытка присвоения отрицательного значения. Проверку выполним для
двух отрицательных чисел — для –1 и самого большого допустимого отрицательного числа типа int. В данных тестовых случаях мы будем ждать
66
возникновения исключения ArgumentException, соответственно форма записи негативного тестового случая несколько изменится:
[TestCase(-1, ExpectedException = typeof(ArgumentException), TestName = “Тестирование Count при присваивании -1.”)]
[TestCase(int.MinValue, ExpectedException =
typeof(ArgumentException), TestName = “Тестирование Count при
присваивании минимально допустимого целого числа.”)]
После запуска негативных тестов, они получили статус Failed.
Рисунок 4.6 — Негативный юнит-тест провален
Данный статус означает, что при подаче некорректных данных исключение в свойстве Count не возникло, что показывает неправильную
реализацию свойства Count. Следовательно, в сеттер свойства Count необходимо добавить проверку на положительность входного значения.
12. Аналогичным образом выполняется тестирование метода Divide.
Однако здесь возможны более хитрые тестовые случаи — деление на 0,
равенство одного из входных аргументов double.NaN или double.Infinity.
При передаче в метод объекта ссылочного типа также стоит выполнять
проверки на равенство объекта null.
13. Выполните тестирование ваших классов проекта Model. Для каждого класса создайте отдельный тестирующий класс. Для каждого общедоступного метода класса напишите тест с позитивными и негативными
тестовыми случаями. Позитивные сценарии составьте на основе анализа
граничных условий, негативные — исходя из назначения метода. По каждому методу ожидается не менее 5 проверяемых тестовых случая. Исправьте реализацию методов, если в результате выполнения тестов вы обнаружите ошибку.

Была ли полезна данная статья?
Да
61.07%
Нет
38.93%
Проголосовало: 1102

или напишите нам прямо сейчас:

⚠️ Пожалуйста, пишите в MAX или заполните форму выше.
В России Telegram и WhatsApp блокируют - сообщения могут не дойти.
Написать в MAXНаписать в TelegramНаписать в WhatsApp