Содержание

Тесты, NUnit, Assert

По-хорошему, все для стабильной работы надо тестировать. Как и люди пинают роботов в Boston Dynamics чтобы посмотреть, насколько они стабильны, так и мы должны придумать всевозможные тесты на проверку стабильности и вариативности написанного нами кода. Сделать это можно при помощи библиотеки NUnit и отдельного проекта.

Я не научу вас как правильно составлять тест-кейсы, видам тестирования и прочему огромному теоретическому бекграунду тестирования, так как это очень большой пласт информации, который нужно рассматривать в отдельных курсах. Но, я кратко покажу вам, каким образом можно тестировать свой код на C#


Настройка главного проекта

У меня есть маленькое приложение, которое ничего не делает, просто имеет пустой класс Program.cs

Код Program.cs

…один класс TestData который хранит в себе тестовые данные некоторых файлов

Код TestData.cs

namespace тесты {     public class TestData     {         //тут имитация того, что код берет файлы         //на самом деле - просто возвращает лист с названиями рандомных файлов         public List<string> GetFiles()         {             List<string> list = new List<string>             {                 "file. txt",                 "file2.log",                 "file3.exe"             };             return list;         }     } }

…и один класс FileManager, который берет все «файлы» из первого класса, а потом смотрит, есть ли в этом листе запрошенный файл.

Код FileManager.cs

namespace тесты {     class FileManager     {         //метод, который берет все файлы из первого класса                 public bool FindFileByName(string fileName)         {             //вот тут берет             TestData obj = new TestData();             List<string> files = obj.GetFiles();                         //a потом ищет нужный файл и возвращает true если нашел             foreach (var file in files)             {                 if (file.Contains(fileName))                     return true;             }                         //false если не нашел             return false;         }     } }

Мне и не требуется иметь код в Program.cs либо в любой другой основной программе. Тестируем мы именно отдельные классы (модули), а это значит, что приложение должно быть модульным (разделенным на классы).


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

Чтобы начать тестирование, нам необходимо создать отдельный проект. Для этого ПКМ нажмем по решению -> добавить -> создать проект

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

Перед нами появится то же самое окно, которое появляется, когда мы создаем новый проект. В поиске мы должны написать NUnit – это библиотека, при помощи которой мы будем создавать тесты. Выберем самый первый появившийся вариант, для C#

Поиск проекта Nunit

Далее мы как-либо называем проект, снова выбираем версию, и создаем. Все как при создании любого другого приложения

При создании перед нами появится класс с ошибками. Это нормально, ошибки появляются потому, что проект пока что только строится и докачивает пакет NUnit (этот пакет вы, кстати, можете найти в управление пакетами Nuget). Как только он все докачает, то все станет зеленым. Важно: для того, чтобы все загрузилось, у вас должен быть интернет

Загрузка пакетов

Разберем подробнее что здесь что

Внутри класса Tests хранятся 2 метода – Setup и Test1. Эти два метода помечены какой-то штукой в квадратных скобках – атрибутами. Этот атрибут задает поведение для метода:

  • Атрибут SetUp говорит методу запустится перед всеми тестами, чтобы их настроить (создать переменные, задать первоначальные значения и прочее)
  • Атрибут Test говорит методу, ну, быть тестом. Без этого атрибута Visual Studio подумает, что это самый обычный метод, как и все те, что мы делали до этого, и не сможет запустить тест. Так что в каждом методе, который должен быть тестом, должен быть этот атрибут Test

Внутри метода Test1 мы видим одну строчку кода – Assert.Pass(); - это, на данный момент, заглушка. При помощи класса Assert проводятся тесты, а Pass – просто метод, который сделает тест намеренно пройденным, не проверяя ничего.


Работа с тестами

Внутри Assert есть огромное количество проверок: IsNull – равна ли переменная Null, Less – меньше ли переменная n-ому значению, Negative – является ли значение меньше нуля и прочее прочее прочее. Опять же, список огромен, все что нам требуется – написать Assert. и искать в появившемся списке интересный нам тест

Список методов у Assert

Я верну Assert.Pass(); чтобы показать, как работают тесты

Чтобы запустить все тесты внутри решения, нужно перейти во вкладку «Тест» и выбрать «Запуск всех тестов»

Запуск тестов

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

Результат тестов

За тест будет считаться каждый метод. Если внутри одного метода есть, например, 5 Assert-ов, и один из них не выполнился, весь тест считается за невыполненный.

Теперь, я хочу протестировать свои два класса, которые я показала в самом начале лекции. Для этого мне нужно сначала подключить проект (Зависимости\Ссылки у проекта с тестами -> Добавить ссылку на проект и галочку у нужного проекта)

Добавление зависимости

А потом нужно создать переменные с ними, их я буду делать в SetUp

Настройка метода Setup

using тесты; {     namespace TestProj     {         public class Tests         {             TestData testData;             FileManager fileManager;                         [SetUp]             public void Setup()             {                 testData = new TestData();                 fileManager = new FileManager();             }         }     } }

Напомню, что TestData отвечает за файлы, а FileManager – за поиск файлов из TestData

Напишу три теста для TestData – создался ли лист (не null), не пустой ли он (лист.count > 0) и точно ли там названия файлов (элемент листа имеет точку)

Точно также для FileManager – три теста – находится ли нужный файл, найдется ли пустое название (не должно), и найдется ли что-то если я передам null (опять же, не должно)

Заметьте, что каждый тест помечен атрибутом Test, а сами тесты сделаны через Assert в отдельном методе

using тесты; {     namespace TestProj     {         public class Tests         {             TestData testData;             FileManager fileManager;                         [SetUp]             public void Setup()             {                 testData = new TestData();                 fileManager = new FileManager();             }                         [Test]             public void ListTest1()             {                 Assert.IsNotNull(testData. GetFiles());             }                         [Test]             public void ListTest2()             {                 Assert.Greater(0, testData.GetFiles().Count);             }                         [Test]             public void ListTest3()             {                 var list = testData.GetFiles();                                 foreach (var item in list)                 {                     Assert.IsTrue(item.Contains("."));                 }             }             [Test]             public void FileTest1()             {                 Assert.IsTrue(fileManager.FindFileByName("file2.log"));             }                         [Test]             public void FileTest2()             {                 Assert. IsFalse(fileManager. FindFileByName(""));             }                         [Test]             public void FileTest3()             {                 Assert.IsFalse(fileManager. FindFileByName(null));             }         }     } }

Запущу все тесты и увижу следующее. Во первых – когда он искал пустоту, он нашел такой файл, хотя не должен был. А также, когда мы отправили туда null, код выдал ошибку, хотя опять же, не должен был.

Ошибка в результатах тестов

Работа тестировщика на этом этапе заканчивается, снова включается разработчик. При помощи таких тестов мы можем понять поведение нашего кода и исправить его. Например, я поправлю код в FileManager так, чтобы все тесты были пройдены

Тогда, код в FileManager.cs будет выглядеть вот так

namespace тесты {     class FileManager     {         public bool FindFileByName(string fileName)         {             //добавлю строку для null             if (fileName == null) return false;                         TestData obj = new TestData();             List<string> files = obj.GetFiles();                         //a потом ищет нужный файл и возвращает true если нашел             foreach (var file in files)             {                 //изменю условие с Contains на ==                 if (file == fileName)                     return true;             }                         //false если не нашел             return false;         }     } }

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

Хорошие результаты тестирования

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