Приклад створення Unit-тесту в Microsoft Visual Studio – C++

Приклад створення Unit-тесту в Microsoft Visual Studio – C++

У даній темі описується покроковий процес створення найпростішого Unit-тесту в системі Microsoft Visual Studio 2010 (C++) для додатку типу CLR Console Application. Використовуючи даний приклад, можна навчитись створювати власні тести. Приклад також демонструє використання класу Assert для проведення тестування роботи функцій.


Зміст


Умова задачі

Для додатку типу CLR Console Application розробити Unit-тест, що тестує роботу функції Max(), яка визначає максимальний елемент з трьох чисел, що є вхідними параметрами функції.

Для функції Max() встановити метод тестування TestMax(). Перевірити роботу функції.

Виконання

1. Створити додаток за шаблоном CLR Console Application

Після запуску Microsoft Visual Studio потрібно вибрати

File->New Project...

У результаті відкриється вікно New Project (рисунок 1), в якому потрібно вибрати шаблон

Visual C++ -> CLR Console Application

Ім’я проекту задати MaxApp (або якесь інше). У нашому випадку папка для проекту встановлена як “E:\Test\” (поле “Location:”).

Visual Studio шаблон CLR Console Application створення додаток

Рис. 1. Створення додатку за шаблоном CLR Console Application

Після вибору OK, буде створено додаток типу CLR Console Application.

Після створення додатку, вікно текстової частини Microsoft Visual Studio буде мати приблизний вигляд, як показано на рисунку 2.

Visual Studio додаток Console Application

Рис. 2. Вигляд додатку після створення

Як видно з рисунку 2, модуль MyApp.cpp містить підключення модуля “stdafx.h” та функцію main(), яка є точкою входу у програму (ця функція асоціюється з програмою на мові C++).

2. Реалізація функції Max()

Перед оголошенням функції main() вводиться текст функції Max(), який має наступний вигляд:

// функція, яка знаходить максимальне значення між трьома цілими числами
int Max(int a, int b, int c)
{
    int max = a;
    if (max<b) max = b;
    if (max<c) max = c;
    return max;
}

Саме цю функцію потрібно буде протестувати з допомогою Unit-тесту в Microsoft Visual Studio.

3. Текст програми, яку потрібно протестувати

На даний момент текст програми, яку потрібно протестувати, має вигляд:

// UnitTestApp01.cpp : Defines the entry point for the console application.
// MaxApp.cpp : main project file.
#include "stdafx.h"
using namespace System;

// функція, яка знаходить максимальне значення між трьома цілими числами
int Max(int a, int b, int c)
{
    int max = a;
    if (max<b) max = b;
    if (max<c) max = c;
    return max;
}

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Unit-test in MS Visual Studio.");
    return 0;
}

Оскільки, ця програма буде тестуватись з іншого модуля тестування, то у функції main() більше нічого вводити не потрібно. Тому що, згідно з умовою задачі, потрібно протестувати роботу функції Max(). А це вже буде здійснюватись з модуля тестування. На даний момент наша програма готова до тестування.

4. Створення тесту

Тест створюється окремим проектом (Project) у рішенні (Solution). Програма, яка буде тестуватись не знає про це. Програма-тест, яка буде тестувати викликає функції програми, що тестується. У нашому випадку програма-тест буде викликати функцію

int Max(int, int, int);
4.1. Додавання нового проекту до рішення

Для створення тесту потрібно створити новий проект у рішенні (Solution). Для цього у Visual Studio викликається послідовність команд

File -> Add -> New Project ...

У результаті відкриється вікно “Add New Project”, зображене на рисунку 3.

Visual Studio вікно "Add New Project"

Рис. 3. Вікно “Add New Project”

У вікні вибирається група шаблонів Visual C++ – Test. З відображених шаблонів вибирається шаблон проекту “Test Project”. У полі “Name” вказується ім’я проекту, що буде тестувати нашу програму. Потрібно задати, наприклад, TestMaxApp. Проект розміщується в окремій папці “E:\Test\MaxApp”.

Після вибору OK система створює нові файли проекту який буде тестувати, як показано на рисунку 4. Створюється файл (модуль) з іменем “UnitTest1.cpp”. У цьому файлі потрібно ввести програмний код, що буде тестувати функцію Max() з модуля MaxApp.cpp.

Visual Studio утиліта Solution Explorer

Рис. 4. Текст модуля UnitTest1.cpp. Вікно утиліти Solution Explorer з відображеними проектами TestMaxApp та MaxApp

4.2. Структура рішення

Як видно з рисунку 4, утиліта Solution Explorer відображає структуру рішення (Solution Items), яке містить два проекти:

  • проект MaxApp. Це проект, створений за шаблоном CLR Console Application з функцією Max(), яку потрібно протестувати;
  • проект TestMaxApp. Цей проект призначений для тестування функцій проекту MaxApp. Програмний код, що тестує функцію Max(), буде вноситись у файл проекту UnitTest1 проекту TestMaxApp.

Обидва проекти можуть виконуватись незалежно один від одного.

4.3. Текст файлу тесту “UnitTest1.cpp”. Атрибути [TestMethod] та [TestClass]

У проекті TestMaxApp головним є файл тесту UnitTest1.cpp. У цьому файлі розміщуються методи, що будуть тестувати функції проекту “MaxApp.cpp”. Проект TestMaxApp може містити будь-яку кількість файлів, що містять тести (наприклад, UnitTest2.cpp, UnitTest3.cpp і т.д.).

Лістинг файлу UnitTest1.cpp, сформований MS Visual Studio, наступний:

#include "stdafx.h"
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;

using namespace Microsoft::VisualStudio::TestTools::UnitTesting;

namespace TestMaxApp
{
    [TestClass]
    public ref class UnitTest1
    {
        private:
        TestContext^ testContextInstance;

        public:
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>

        property  Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ TestContext
        {
            Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ get()
            {
                return testContextInstance;
            }

            System::Void set(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ value)
            {
                testContextInstance = value;
            }
        };

        #pragma region Additional test attributes
        //
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //static void MyClassInitialize(TestContext^ testContext) {};
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //static void MyClassCleanup() {};
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //void MyTestInitialize() {};
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //void MyTestCleanup() {};
        //
        #pragma endregion

        [TestMethod]
        void TestMethod1()
        {
            //
            // TODO: Add test logic here
            //
        };
    };
}

Як видно з вищенаведеного коду, файл містить клас з іменем UnitTest1. У класі є загальнодоступний (public) метод з іменем TestMethod1(). Перед реалізацією методу TestMethod1() розміщується атрибут [TestMethod]. Це означає, що у тіло методу потрібно вписати код, що буде тестувати функції проекту MaxApp.

У класі можна вписувати будь-яку кількість методів, які будуть тестувати різні функції з різних модулів. Головне, щоб ці методи були помічені атрибутом [TestMethod]. Наприклад, якщо потрібно додати другий метод тестування з іменем MySecondTestMethod(), то у тіло класу потрібно вписати приблизно наступний код:

...
[Test Method]
void MySecondTestMethod()
{
    // тестувальний програмний код методу MySecondTestMethod()
    // ...
}
...

Аналогічно, перед класом UnitTest1 розміщується атрибут [TestClass]. Це означає, що в класі є методи, що тестують.

4.4. Виконання змін у тексті модуля UnitTest1

Допускається змінювати назви методів та додавати нові методи, які помічені атрибутом [TestMethod] у модулі UnitTest1.cpp. Враховуючи це, у тексті модуля UnitTest1.cpp потрібно метод TestMethod1() перейменувати на TestMax().

Після виконаних змін, скорочений текст модуля файлу UnitTest1.cpp буде мати вигляд:

#include "stdafx.h"
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;

namespace TestProjectApp01
{
    [TestClass]
    public ref class UnitTest1
    {
        private:
        TestContext^ testContextInstance;

        public:

        ...

        [TestMethod]
        void TestMax()
        {
            //
            // TODO: Add test logic here
            //
        };
    };
}
4.5. Підключення модуля “MaxApp.cpp” проекту MaxApp до проекту TestMaxApp

Щоб доступитися до функції Max() модуля “MaxApp.cpp” проекту MaxApp з проекту TestMaxApp, потрібно викликати цей модуль з допомогою директиви #include.

Існує 2 способи такого підключення:

  • підключити файл “MaxApp.cpp”, вказавши його повне ім’я на диску (або з іншого джерела);
  • у посиланнях на збірки Microsoft Visual Studio налаштувати папку з проектом MaxApp, щоб вона підключалась автоматично. Після цього можна звертатися до файлу “MaxApp.cpp” за його скороченим ім’ям.

У даній темі описуються обидва способи.

4.5.1. Спосіб 1. Підключення з задаванням повного імені

Цей спосіб є найпростіший. Він є зручним, якщо потрібно підключити у проект невелику кількість файлів для тестування.

У проекті TestMaxApp у файлі “UnitTest1.cpp” після підключення просторів імен потрібно задати такий рядок:

#include "E:\\Test\\MaxApp\\MaxApp\\MaxApp.cpp"

Тут вказується повне ім’я на диску файлу MaxApp.cpp, в якому розміщується функція Max(), яку потрібно протестувати.

4.5.2. Спосіб 2. Підключення з задаванням скороченого імені

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

У нашому випадку потрібно підключити папку:

E:\Test\MaxApp\MaxApp\

у перелік посилань на збірки (проекти), що автоматично підключаються до проекту TestMaxApp. Після цього, можна буде підключати модуль MaxApp.cpp за скороченим ім’ям

#include "MaxApp.cpp"

уникаючи використання довгого імені як показано у пункті 4.5.1.

Перщ за все викликається команда “References…” з контекстного меню TestMaxApp як показано на рисунку 5. Інший спосіб виклику – команда Project->References… (попередньо потрібно виділити проект TestMaxApp).

Visual Studio вікно посилання збірка

Рис. 5. Виклик вікна перегляду посилань на збірки, що використовуються у проекті TestMaxApp

У результаті відкриється вікно “TestMaxApp Property Pages” яке зображене на рисунку 6.

MS Visual Studio команда "Add New Reference..."

Рис. 6. Вікно TestMaxApp Property Pages, команда “Add New Reference…”

У вікні “TestMaxApp Property Pages” спершу потрібно активувати вкладку “Common Properties” -> “Framework and References”.

Потім потрібно вибрати команду “Add New Reference…”. Ця команда дозволяє додавати у проект нові папки з модулями, методи (функції, ресурси) яких потім можна включати в проект директивою #include. Після вибору команди відкриється вікно Add Reference, яке зображене на рисунку 7.

MS Visual Studio вікно Add Reference проекти

Рис. 7. Вікно Add Reference з відображеними проектами в поточному рішенні

У вікні “Add Reference” у вкладці Project відображаються папки проектів, що використовуються у даному рішенні (Solution). У нашому випадку відображається тільки один проект MaxApp, який розміщується у папці

E:\Test\MaxApp\MaxApp

Після вибору на OK відбудеться повернення у попереднє вікно, в якому в переліку посилань на збірки буде відображено посилання на проект MaxApp.

MS Visual Studio вікно "TestMaxApp Property Pages"

Рис. 8. Вікно “TestMaxApp Property Pages” після додавання проекту MaxApp у перелік загальнодоступних збірок

Це ще не все. Наступним кроком потрібно підключити папку з проектом MaxTest в перелік “Include Directories”.

Щоб зробити це, потрібно спочатку активувати рядок

Configuration Properties -> VC++ Directories

як показано на рисунку 9.

Visual Studio вікно TestMaxApp Property Pages рядок "Include Directories"

Рис. 9. Вікно TestMaxApp Property Pages, рядок “Include Directories”

У переліку “General” вибирається “Include Directories”. У результаті з’являється спадний список, в якому потрібно вибрати команду “<Edit…>”. Після цього відкриється вікно “Include Directories”, яке показане на рисунку 10.

Visual Studio команда "New Line"

Рис. 10. Команда “New Line” та кнопка вибору папки з файлами, що підключаються

У вікні “Include Directories” потрібно додати новий рядок командою “New Line” та вибрати папку з проектом MaxApp, як показано на рисунку 10. Після вибору кнопки “…” відкриється стандартне вікно Windows для вибору потрібної папки. У нашому випадку потрібно вибрати папку

E:\Test\MaxApp\MaxApp

Після вибору, вікно Include Directories матиме вигляд як показано на рисунку 11.

Visual Studio вікно Include Directories

Рис. 11. Вікно Include Directories після вибору папки E:\Test\MaxApp\MaxApp

Для переходу до попереднього вікна потрібно вибрати OK.

Visual Studio вікно TextMaxApp Property Pages

Рис. 12. Вікно TextMaxApp Property Pages після задавання рядка “Include Directories”

Для переходу до написання програмного коду тестування потрібно вибрати OK.

Після виконаних дій, усі файли з папки

E:\Test\MaxApp\MaxApp

можна підключати за скороченим іменем, наприклад:

#include "MaxApp.cpp"
4.6. Написання програмного коду для проведення тестування у методі TestMax()

Програмний код, що тестує функцію Max() вписується у тіло методу TestMax() модуля “UnitTest1.cpp”. Фрагмент програмного коду методу TestMax() виглядає наступним чином:

...

[TestMethod]
void TestMax()
{
    //
    // TODO: Add test logic here
    //
    int t;
    t = Max(5, 6, 7);
    Microsoft::VisualStudio::TestTools::UnitTesting::Assert::AreEqual(t, 6);
};

...

У вищенаведеному коді викликається функція AreEqual() з класу Assert. Ця функція порівнює значення, яке було повернуте з функції Max() та число 6. У даному випадку, відбувається порівняння числа 7 (максимум) з числом 6. Для такого варіанту тест не буде виконуватись, тому що 7 не дорівнює 6. У результаті функція Assert::AreEqual() викине виключну ситуацію, що буду відображатись у спеціальному вікні (див. п.5).

5. Запуск тесту на виконання та перевірка результату тестування

У Microsoft Visual Studio для роботи з Unit-тестами реалізовано спеціальне меню команд, яке називається Test.

Щоб запустити тест на виконання, потрібно вибрати одну з команд

Test -> Run -> Tests in Current Context

або

Test -> Run -> All Tests in Solution

як показано на рисунку 13.

Visual Studio команда запуск тесту

Рис. 13. Виклик команди запуску тестування та перегляд результату

Після запуску тесту, результат можна переглянути у нижній частині у вікні Test Results. Як видно, тест не здано. Це є логічно, тому що у функції Assert::AreEqual() ми порівнюємо числа 6 та 7, які є відмінні. Тут навмисно введено число 6 замість 7.

Якщо замість числа 6 ввести правильну відповідь – число 7 (максимуму між 5, 6, 7), то тест буде здано. У цьому випадку текст методу TestMax() буде наступним:

...

[TestMethod]
void TestMax()
{
    //
    // TODO: Add test logic here
    //
    int t;
    t = Max(5, 6, 7);
    Microsoft::VisualStudio::TestTools::UnitTesting::Assert::AreEqual(t, 7);
};

...

Вікно результату зображене на рисунку 14.

Visual Studio результат тестування

Рис. 14. Результат тестування для випадку, коли ввести правильну перевірку

Тепер можна зробити висновок про те, що функція Max() розроблена правильно

6. Текст модуля UnitTest1

Нижче приводиться текст модуля UnitTest1.cpp, який тестує функцію Max() з модуля “MaxApp.cpp”:

#include "stdafx.h"
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;

// спосіб 1 - задавання повного імені
// #include "E:\\Test\\MaxApp\\MaxApp\\MaxApp.cpp"

// спосіб 2 підключення MaxApp за скороченим іменем
#include "MaxApp.cpp"

namespace TestMaxApp
{
    [TestClass]
    public ref class UnitTest1
    {
        private:
        TestContext^ testContextInstance;

        public:
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>

        property Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ TestContext
        {
            Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ get()
            {
                return testContextInstance;
            }

            System::Void set(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ value)
            {
                testContextInstance = value;
            }
        };

        #pragma region Additional test attributes
        //
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //static void MyClassInitialize(TestContext^ testContext) {};
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //static void MyClassCleanup() {};
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //void MyTestInitialize() {};
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //void MyTestCleanup() {};
        //
        #pragma endregion

        [TestMethod]
        void TestMax()
        {
            //
            // TODO: Add test logic here
            //
            int t;
            t = Max(5, 6, 7);
            Microsoft::VisualStudio::TestTools::UnitTesting::Assert::AreEqual(t, 7);
        };
    };
}
7. Підсумок. Взаємодія між проектами

У даній роботі у рішенні (Solution) сформовано два проекти. Один проект MaxApp містить функцію Max() яку потрібно протестувати. Другий проект TestMaxApp містить методи, які тестують.

У Microsoft Visual Studio кожен з проектів запускається з допомогою різних команд меню. Так, проект MaxApp запускається стандартним способом з меню Run. А проект який тестує TestMaxApp запускається зі спеціального меню Test.


Зв’язані теми