Статьи

Введение в модульное тестирование в .NET

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

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

Итак, начнем с кода. У меня есть пример тестового приложения и пример класса, содержание которого изложено ниже:

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace Sandbox{    class Some    {        public string GetTheValue(string a, int x)        {            return a + x.ToString();        }        public string SampleString(string b, string c)        {            return b + c;        }    }}

Здесь у меня есть две функции, обе возвращающие строки, но одна принимает строковые параметры и параметры int, а другая — два строковых параметра. Теперь, чтобы создать модульные тесты для функций, щелкните правой кнопкой мыши объявление функции и выберите «Создать модульные тесты …»

Появится окно, в котором вы можете выбрать классы, методы, функции и свойства из текущего класса (а также из других классов), для которого вы хотите использовать для создания модульных тестов.

На изображении видно, что я выбрал только SampleString в качестве тестируемого объекта. Тем не менее, я также могу выбрать обе функции в классе. После этого в нижней части появляется выпадающее меню «Выходной проект», в котором вы можете выбрать целевой язык программирования для модульных тестов. Поскольку мой основной проект написан на C #, я также создам тестовый проект C #.

При запросе имени введите любое имя, если оно поддерживается IDE. Я назвал свой тестовый проект MyTest.

Теперь вы можете видеть, что к вашему решению добавлен дополнительный проект:

Он имеет только один активный класс с именем SomeTest.cs — это фактический класс тестирования для существующего класса Some.cs в основном проекте. Если вы откроете его, вы увидите автоматически сгенерированный код. После очистки (пока я не концентрируюсь на некоторых деталях), код должен выглядеть примерно так:

using Sandbox;using Microsoft.VisualStudio.TestTools.UnitTesting;using System;namespace MyTest{    [TestClass()]    public class SomeTest    {        [TestMethod()]        public void SampleStringTest()        {            Some target = new Some(); // TODO: Initialize to an appropriate value            string b = string.Empty; // TODO: Initialize to an appropriate value            string c = string.Empty; // TODO: Initialize to an appropriate value            string expected = string.Empty; // TODO: Initialize to an appropriate value            string actual;            actual = target.SampleString(b, c);            Assert.AreEqual(expected, actual);            Assert.Inconclusive("Verify the correctness of this test method.");        }        [TestMethod()]        public void GetTheValueTest()        {            Some target = new Some(); // TODO: Initialize to an appropriate value            string a = string.Empty; // TODO: Initialize to an appropriate value            int x = 0; // TODO: Initialize to an appropriate value            string expected = string.Empty; // TODO: Initialize to an appropriate value            string actual;            actual = target.GetTheValue(a, x);            Assert.AreEqual(expected, actual);            Assert.Inconclusive("Verify the correctness of this test method.");        }    }}

Один из отличительных элементов, который вы заметите первым, если присутствуют атрибуты теста: [TestClass ()] и [TestMethod ()] — они в основном определяют, что тестируется. Вы можете видеть, что тестовый класс является практически идентичной копией класса Some, однако методы структурированы немного иначе. Прежде всего, они не имеют входных параметров и имеют тип void.

Это потому, что тесты используются, чтобы опробовать рабочий механизм блока. Следовательно, проверка не возвращает результаты, а просто выполняет набор действий.
Давайте начнем с SampleStringTest. Внутри этого метода я создаю экземпляр класса Some, а затем создаю две строковые переменные, которые являются параметрами, передаваемыми исходной функции. Я также устанавливаю их значения, так как тест будет выполнен против них. Ожидаемая переменная — это результат, который разработчик ожидает получить при выполнении функции (возвращаемое значение). Фактическая переменная хранит значение, возвращаемое после выполнения.

Существует также метод Assert.AreEqual, который проверяет, совпадает ли ожидаемое значение с возвращаемым. Если это так, то тест проходит. Если это не так, тест не пройден.

По умолчанию значения, указанные для переменных, равны нулю. Я собираюсь изменить это. Для того же метода SampleStringTest я собираюсь использовать этот код:

[TestMethod()]public void SampleStringTest(){    Some target = new Some(); // TODO: Initialize to an appropriate value    string b = "Unit"; // TODO: Initialize to an appropriate value    string c = " Test"; // TODO: Initialize to an appropriate value    string expected = "Unit Test"; // TODO: Initialize to an appropriate value    string actual;    actual = target.SampleString(b, c);    Assert.AreEqual(expected, actual);}

Обратите внимание, что я также удалил вызов метода Assert.Incoclusive. Обычно используется, чтобы показать, что состояние теста не может быть определено. В этом случае я только хочу видеть, терпит ли это неудачу или нет. Я также указал некоторые тестовые значения и ожидаемое значение. Этот тест должен пройти, так как я предоставил правильные тестовые значения и правильное ожидаемое значение.

На панели инструментов «Инструменты тестирования» нажмите кнопку «Выполнить тесты в текущем контексте», когда курсор находится внутри метода SampleStringTest:

Теперь вы должны увидеть диалог Результаты теста внизу:

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

Та же процедура, которая была применена к методу SampleStringTest, может быть применена и к другому методу тестирования.

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