Труды Международного симпозиума «Надежность и качество», 2016, том 1
Большинство библиотек С++ в настоящее время доступны и отлажены на многих платформах, многие из них с открытым кодом. Но не смотря на меньший ассортимент библиотек С# легко покрывает большинство потребностей разработки, кроме того они как правило лучше вписываются в шаблоны проектирования.
Напрашивается вопрос «А какой из языков лучше?», но ответ на него дать невозможно. С+ + и С# одновременно похожие и очень разные языки. И выбор одного из них почти полностью зависит от стоящей задачи.
УДК 004.4'233 Трусов Е.В.
ФГБОУ ВО «Пензенский государственный университет», Пенза, Россия
О МОДУЛЬНОМ ТЕСТИРОВАНИИ НА С++
В данной статье описаны положительные стороны модульного тестирования в общем и приведены примеры на языке c++.
При написании больших проектов и их поддержке возникает момент, когда определенный участок кода нужно подкорректировать или и вовсе переписать. Но как быть уверенным, что при рефакто-ринге не измениться функционал в функциях-потомках итп. Одним из способов обезопасить себя от этого является модульное тестирование.
Обратимся к Википедии :
Модульное тестирование, или юнит-тестирование
(англ. unit testing) — процесс в программировании, позволяющий проверить на корректность отдельные модули исходного кода программы.
Идея состоит в том, чтобы писать тесты для каждой нетривиальной функции или метода. Это позволяет достаточно быстро проверить, не привело ли очередное изменение кода к регрессии, то есть к появлению ошибок в уже оттестированных местах программы, а также облегчает обнаружение и устранение таких ошибок.
Следовательно, тесты позволяют активно выявлять баги в тестируемых участках.
Достаточно часто на интернет ресурсах разгораются споры по поводу так ли они необходимы, с одной стороны помогает при написании и отладки программы, но с ними разрастается исходный код, а так же уходит время у разработчиков.
Можно выделить несколько случаев, когда не требуется тесты:
Достаточно небольшой и простой код, в котором нет сложной логики. И его быстрее проверить "руками" .
Приложение необходимое для демонстрации своих знаний и умений, на которое посмотрят, проверят функционал и забудут (курсовые работы, выставки).
Сжатые сроки проекта.
Вы всегда пишите превосходный код, полностью уверены в его работоспособности, обладаете феноменальной памятью.
Во всех остальных случаях желательно писать юнит-тесты, а так же проверять работоспособность с их помощью после различных модификаций.
Существуют следующие типы проектов
Без покрытия тестами. Обычно мало кто понимает, как работает вся программа целиком, за исключением ведущих программистов, которые и писали данный "шедевр". Новые специалисты, назначенные для корректировки участков кода, предпочитают переписывать код с нуля.
С тестами, которые никто не запускает. Если тесты есть, но они не запускаются и не поддерживаются, то какой от них ожидается результат -неизвестно. С данными проектами дела обстоят получше, есть понимание, какой участок кода что должен делать.
С качественным покрытием. Тесты проходят. Это наиболее качественные проекты, с ними легко работать. В данном случае проект зависит не от людей, поэтому текучесть кадров не сильно страшна.
Стоит упомянуть основные принципы модульного тестирования.
Тесты должны быть маленькими и быстрыми.
Тесты должны проходить автоматически. Лучше всего, если они будут включены в сборку проекта, тогда если какой тест зафейлится, прервется вся сборка. Это гораздо удобнее, чем запускать их отдельно после сборки самого проекта.
Тесты не должны зависеть друг от друга и от порядка их следования.
Тесты не должны зависеть от окружения и файлов.
Для каждого класса следует завести отдельный тестовый класс.
Легко читаться и поддерживаться.
Отделять тесты от основного проекта.
Единая система именования тестов.
Отдельно уточню про 4й пункт. Зачастую, информацию для обработки в программе разработчики берут из БД, фалов, различных удаленных серверов и прочего. Чтобы воссоздать получаемые данные в тестах они используют файлы с необходимой информацией и на их основе проверяют функционал. В данном случае сильно захламляется проект и теряется его видимость.
Но обо всем по порядку.
Выбор логического расположения тестов в проекте.
Тесты должны быть частью контроля версий. В зависимости от проекта они могут быть организованы по-разному. Рекомендуется: при монолитном приложении, переместить все тесты в папку Tests; если различных плагинов и составляющих, хранить тесты в папке с каждым компонентом.
Выбор способа именования проекта с тестами.
Самый простой и прижившийся способ - добавление в конец названия проекта "test". Например, проект <PROGECT NAME> проект с тестами < PROGECT_NAME _TESTS>.
Использование такого же способа именования для тестовых классов.
Класс Clock, тестовый класс ClockTest. Каждый тестирующий класс должен тестировать только одну сущность.
Выбрать понятный способ именования методов тестирующих классов.
В название метода желательно включить следующее: имя тестируемого метода, сценарий, ожидаемое поведение.
Выбрать тестовый фреймворк и библиотеку, которые вам подходит.
В сущности, можно запускать тесты из консольного приложения, но зачем, если есть удобные приложения, которые во многом облегчат вашу работу.
На данный момент существует огромное количество библиотек для написания модульных тестов под C++. Вот некоторые из них:
Boost::Test
Boost — одна из самых известных (и сам больших) библиотек для C++, а Boost::Test - это Фреймворк для тестирования, входящий в неё и построенный на макросах. Она достаточно громоздкая, не самая лучшая документация, но при этом во многом удобная.
QTestLib
Также не менее известная библиотека, но по отзывам сложновата, да и тянуть всё QT ради тестов не оправдано.
UnitTest++
Довольно не плохая и популярная вещь, но бедно-вата документация.
CxxTest
Достаточно хорошая xUnit- подобная библиотека для написания модульных тестов.
Не нужно ничего встраивать в исходный код, не
Труды Международного симпозиума«
нужна установка, не использует сторонних библиотек. Но требует Perl или Python.
После выбора всего вышеперечисленного нужно понять, что следует тестировать, а что нет.
Здесь все зависит только от вас самих. Можно тестами покрыть 100% кода, но это большая трата ресурсов. Золотая середина, по моему мнению -нетривиальные публичные функции.
Каждый тест должен проверять только одну вещь. Если процесс слишком сложен (например, покупка в интернет магазине), разделите его на несколько частей и протестируйте их отдельно. Если вы не будете придерживаться этого правила, ваши тесты станут нечитаемыми, и вскоре вам окажется очень сложно их поддерживать.
Отдельно я бы хотел рассмотреть boost test framework
Каждый файл, использующий boost test framework, должен подключать соответствующий заголовочный файл:
#include <boost/test/unit test.hpp>
Как известно, любая программа должна иметь точку входа (функцию, с которой начинается выполнение программы). В зависимости от того, как организован проект, вы можете либо написать эту функцию сами, либо доверить всю работу Boost. Функция main будет добавлена автоматически, если перед подключением unit test.hpp объявлены константы BOOST_TEST_MAIN и BOOST_TEST_DYN_LINK. Вызовы всех тестов проекта будут автоматически помещены в сгенерированную функцию.
При запуске тестирования программа будет последовательно входить в наборы и выполнять вложенные тесты. Чтобы проследить этот процесс по шагам - можно передать исполняемому файлу аргумент -loglevel=test suite.
Для описания тестовых случаев применяется макрос BOOST_AUTO_TEST_CASE, содержащий имя и код теста. Код теста содержит специальные макросы, проверяющие соответствие фактических результатов работы функции ожидаемым. Макросы отличаются уровнем предупреждения (CHECK - ошибка, REQUIRE - критическая ошибка, WARN - предупреждение). Среди макросов есть следующие:
BOOST CHECK (условие) - сообщает об ошибке, если условие ложно;
BOOST_REQUIRE_EQUAL(apryMeHT_1, аргумент_2) - сообщает о критической ошибке, если аргумент 1 не равен аргумент 2;
BOOST_WABN_MESSAGE(y^OBMe, сообщение) - выводит предупреждение с текстом сообщения, если условие ложно;
BOOST_CHECK_NO_THROW(выpажeниe) - сообщает об ошибке, если при вычислении выражения вырабатывается исключение;
BOOST_CHECK_THROW(выpажeниe, исключение) -сообщает об ошибке, если при вычислении выражения не вырабатывается исключение требуемого типа;
BOOST_CHECK_CLOSE_FRACTION( аргумент_1, аргумент 2, погрешность) - проваливает тест если аргумент 1 не равен аргумент 2 с заданной погрешностью.
Более полный список доступных макросов можно найти в официальной документации.
Пример unit-тестирования с boost test framework
Рассмотрим простой класс, который способен делить и умножать некоторые числа и сохраненять результат:
class Calculator {
public:
explicit Calculator(int value) : Value (value)
{ }
void Divide(int value)
{
if (value == 0) {
throw std::invalid argument ("Деление на ноль!");
}
Value /= value;
}
void Multiply(int value)
{
Value *= value;
}
int Result() const
{
return Value ;
}
private:
int Value ;
};
Тестировать будем следующим образом - сначала вызовем метод Divide с несколькими значениями и сравним результат возвращаемый Result с эталонными значениями, потом проделаем это с методом Multiply.
#include "calculator.h"
#include <boost/test/unit test.hpp>
#define BOOST_TEST_MODULE testCalculator
BOOST_AUTO_TEST_CASE(testCalculator) {
Calculator calculator(12);
BOOST_CHECK_EQUAL(calculator.Result(),
12);
calculator.Divide(3);
BOOST_CHECK_EQUAL(calculator.Result(),
4);
calculator.Divide(2);
BOOST_CHECK_EQUAL(calculator.Result(),
2);
calculator.Multiply(2);
BOOST_CHECK_EQUAL(calculator.Result(),
4);
calculator.Multiply(3);
BOOST_CHECK_EQUAL(calculator.Result(),
12); }
В заключении хотел бы сказать, что unit-тестирование очень удобная функция в программировании, которой не стоит пренебрегать.
УДК 004.4'233 Трусов Е.В.
ФГБОУ ВО «Пензенский государственный университет», Пенза, Россия
РАЗРАБОТКА АВТОМАТИЗИРОВАННОЙ СРЕДЫ СБОРКИ КРОСС-ПЛАТФОРМЕННОГО ПО ДЛЯ ОС СЕМЕЙСТВА LINUX
Введение
При разработке программы в требованиях может быть указана необходимость работоспособности на различных платформах. Порой нужно добавить к существующей программе работоспособность на других платформах, т.к. это может привлечь потенциального клиента к покупке и использованию именно этого ПО. Когда появляется такая потребность,
можно использовать специальные сторонние программы для сборки, но они не всегда могут применимы из-за ограничений функциональности, требований ТЗ и прочих, поэтому иногда самым подходящим вариантом является создание своей собственной сборочной кроссплатформенной системы. Это работа как раз посвящена разработке прототипа такой системы.
Для сборки нам потребуется следующее: