Тестовый код в C С++
Я не знаю, как вы, ребята, тестируете свой код каждый раз, когда вы немного кодируете код и для разных уровней тестирования: модульное тестирование, тестирование интеграции,...
Например, для модульного тестирования функции, которую вы только что написали, вы пишете еще один полный набор основных функций и Makefile для его проверки? Или вы изменяете основную функцию своего проекта для проверки функции. Или вы просто запускаете проект под отладкой и останавливаетесь на том, где функция должна быть вызвана и изменить значения ее аргументов?
Я считаю, что должны быть некоторые удобные и распространенные способы, которыми пользуются большинство людей, и только я не знаю.
Ответы
Ответ 1
xUnit - это семейство модулей модульного тестирования. x заменяется буквой для языка используемой структуры. В настоящее время семья состоит из:
Я работал в проектах с использованием CppUnit с хорошими результатами. Недавно я попытался интегрировать это в автоматическую среду сборки (т.е. Хадсон), и я столкнулся со многими препятствиями.
В идеале, сборка автоматически строит и запускает модульные тесты. В этом случае код запускается из тестовой среды (и, следовательно, имеет собственный основной цикл). Дополнительным осложнением в моем случае является то, что я работаю со встроенными системами; printf не всегда возможен. Я ожидаю, что если вы запустите на ПК, CUnit и CppUnit могут помочь вам в реализации хорошего модульного тестирования. Посмотрите, как использовать результаты; система непрерывной интеграции значительно повысит вашу эффективность.
Еще одна структура, заслуживающая внимания: Maestra. Он полагается на C99 (который Microsoft никогда не реализовал, но для gcc это здорово!)
Ответ 2
Подход Test Driven Development (TDD) заключается в том, чтобы сначала написать тест, увидеть, что он по умолчанию не работает (т.е. новый тест завершился неудачей), затем напишите функцию для прохождения теста.
Таким образом, тестирование становится не запоздалой мыслью, а самой основой вашей методологии разработки.
Поскольку вы можете разрабатывать функцию (метод), прежде чем реализовать объекты, на которых она работает, большинство фреймворков TDD также предоставляют средство для создания "макетных" объектов, которые возвратят ожидаемые результаты до того, как их классы будут фактически реализованы.
Я лично рекомендую Google Test и Google Mock:
http://code.google.com/p/googletest/
http://code.google.com/p/googlemock/
Ответ 3
Сравнение CppTest и CppUnit Я бы пошел с CppTest. CppTest имеет меньше скрытых фреймворков, и IMO легче понять и реализовать. Мне лично нравится видеть главную точку входа. Я также включил Boost Unit Testing Framework. Это не xUnit. Я не поклонник, но если вы уже используете библиотеку Boost, было бы неплохо включить.
CppTest vs CppUnit
• Простота создания unit test и теста люкс. Оба CppUnit и CppTest создают модульные тесты методов класса, с сам класс оснащенный инструментами Класс тестирования. Синтаксис для CppTest немного проще, хотя, с регистрацией теста происходит внутри класса конструктор. В случае CppUnit, дополнительные макросы CPPUNIT_TEST_SUITE и Необходимы CPPUNIT_TEST_SUITE_ENDS.
• Выполнение тестов. CppTest просто вызывает метод run на тесте, а CppUnit использует отдельный Класс TestRunner, метод запуска которого вызывается для запуска тестов.
• Расширение иерархии тестирования. В случай CppTest, он всегда возможно продлить предыдущий тест, создав новый класс, который наследуется от старого. Новый класс определит некоторые дополнительные функции, которые добавляют к unit testбассейн. Вы просто вызываете метод run на объект нового типа класса. CppUnit, напротив, требует, чтобы вы используете макрос CPPUNIT_TEST_SUB_SUITE вместе с наследование классов для достижения того же эффект.
• Создание отформатированного вывода. И то и другое CppTest и CppUnit обладают способностью для настройки вывода. Однако, хотя CppTest имеет полезный, предопределенный формат вывода HTML, CppUnit нет. Однако CppUnit исключительно поддерживает форматирование XML. Оба поддерживают текст и стиль компилятора форматы.
• Создание тестовых приборов. Использовать тест, CppUnit требует, чтобы класс испытаний должен быть получен из CppUnit:: TestFixture. Вы должны предоставить определения для установки и срывные процедуры. В случае CppTest, вам необходимо предоставить определения только для установки и срывные процедуры. Это определенно лучшее решение, поскольку оно клиентский код прост. • Предопределенные поддержка макросов утилиты. Оба CppTest и CppUnit имеют сопоставимый набор макросы для утверждений, обработки поплавков, и так далее.
• Заголовочные файлы. CppTest требует, чтобы вы включаете один заголовочный файл, в то время как код клиента CppUnit должен включать несколько заголовков, таких как HelperMacros.h и TextTestRunner.h, в зависимости от используемые функции.
http://www.ibm.com/developerworks/aix/library/au-ctools3_ccptest/index.html?ca=drs-
CPPTEST
#include "cppTest.h"
class myTestWithFixtures : public Test::Suite {
void function1_to_test_some_code( );
void function2_to_test_some_code( );
public:
myTestWithFixtures ( ) {
TEST_ADD (function1_to_test_some_code) {...};
TEST_ADD (function2_to_test_some_code) {...};
}
protected:
virtual void setup( ) { ... };
virtual void tear_down( ) { ... };
};
int main ( )
{
myTestWithFixtures tests;
Test::TextOutput output(Test::TextOutput::Verbose);
return tests.run(output);
}
http://www.ibm.com/developerworks/aix/library/au-ctools3_ccptest/index.html?ca=drs-
CppUnit
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TextTestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
class mystringTest : public CppUnit::TestFixture {
public:
void setUp() { ... };
void tearDown() { ... };
void function1_to_test_some_code() { ... };
void function2_to_test_some_code() { ... };
CPPUNIT_TEST_SUITE( mystringTest );
CPPUNIT_TEST( function1_to_test_some_code );
CPPUNIT_TEST( function2_to_test_some_code );
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION( mystringTest );
с макросами
int main ()
{
CppUnit::TestSuite* suite = new CppUnit::TestSuite("mystringTest");
suite->addTest(new CppUnit::TestCaller<mystringTest>("checkLength",
&mystringTest::checkLength));
suite->addTest(new CppUnit::TestCaller<mystringTest>("checkValue",
&mystringTest::checkLength));
// client code follows next
CppUnit::TextTestRunner runner;
runner.addTest(suite);
runner.run();
return 0;
}
http://www.ibm.com/developerworks/aix/library/au-ctools2_cppunit/
Рамочная платформа для тестирования блоков
#include <boost/test/unit_test.hpp>
using namespace std;
struct CMyFooTestFixture
{
CMyFooTestFixture() { ... } //SetUp
~CMyFooTestFixture() { ... } //TearDown
void function1_to_test_some_code(CMyFoo& foo) { ... };
void function2_to_test_some_code(CMyFoo& foo) { ... };
}
BOOST_FIXTURE_TEST_SUITE(MyFooTest, CMyFooTestFixture);
BOOST_AUTO_TEST_CASE(function1_to_test_some_code)
{
CMyFoo foo;
function1_to_test_some_code(foo);
}
BOOST_AUTO_TEST_CASE(function1_to_test_some_code2)
{
CMyFoo foo;
function1_to_test_some_code(foo);
}
BOOST_AUTO_TEST_SUITE_END();
http://www.beroux.com/english/articles/boost_unit_testing/
Ответ 4
Я использую googletest/gtest
Ответ 5
Я научился любить googletest/googlemock. Они очень мощная комбинация и проста в использовании. На их страницах вики имеется также большая документация.
googletest:
code.google.com/p/googletest/wiki/GoogleTestPrimer
googlemock:
code.google.com/p/googlemock/wiki/ForDummies
Ответ 6
Обычно я делаю так:
int foo(int bar) {
...
}
#ifdef FOO_UNITTEST
int main(int argc, char *argv[]) {
// tests
}
#endif
И у меня есть makefile, у которого -DFOO_UNITTEST
в CFLAGS
.
Это неуклюже, но у вас всегда есть свои тесты рядом с вашим кодом.
Ответ 7
Мне нравится googletest и googlemock. На самом деле легко настроить и хорошо документировать, здесь есть хорошее введение в структуру.
Ответ 8
Вы посмотрели http://CppUnit.sourceforge.net?
Ответ 9
Вам также следует рассмотреть возможность запуска инструмента для тестирования, чтобы убедиться, что ваши тесты на самом деле достаточны для того, чтобы код был хорошим набором тестов.
См. Задание тестирования SD для C.
Ответ 10
Я люблю UnitTest ++. Это очень легко настроить, и писать тесты проще, чем с типичным любимым, CppUnit. У каждого теста очень мало накладных расходов на кодирование, поэтому вы с большей вероятностью напишите их!
Что касается того, что я тестирую, я стараюсь тестировать публичные интерфейсы классов, но если я просто делаю рефакторинг и разбиваю вещи на более мелкие функции, я не буду писать набор тестов для каждой из этих функций - они должны быть охвачены испытаниями, тестирующими открытый интерфейс. Пока публичный интерфейс работает в соответствии с тестами, все хорошо в мире.
Ответ 11
Я использую boost.test. Я перешел к нему из cppunit, который был хорошим, но слишком похожим на java, это была проблема, потому что junit использует отражение, чтобы найти и запустить ваши тесты, так как это не доступно в С++, вы должны использовать макросы для регистрации своих тестов, в cppunit you должны объявлять, регистрировать и определять свои тесты в трех разных местах. boost.test позволяет вам объявлять, регистрировать и определять свой тест в одном из утверждений, это очень приятно.
Мой общий подход - это новый код TDD и старательно использовать unit test для устаревшего кода. Я тестирую любой код, который отличается на разных платформах, чтобы гарантировать, что они ведут себя одинаково и продолжают вести себя одинаково.
Я структурирую свои проекты так, чтобы каждая библиотека или исполняемый проект также имела проект unit test. Для исполняемых тестов я включаю исполняемые исходные файлы (кроме основного) в тестовый проект и добавляю свой тест в новые файлы. Для тестов библиотеки я обычно просто ссылаюсь на библиотеку, кроме тех случаев, когда я тестирую частные части DLL, тогда я использую исполняемый подход.
Использование CMake позволяет абстрагироваться от любого дублирования между исходным проектом и тестовым проектом. Также CTest хорошо интегрируется с любой инфраструктурой модульного тестирования, которая тестирует пакеты в исполняемых файлах. Это позволяет запускать все тестовые исполняемые файлы в решении за один раз и сообщать сводку результатов. Он также интегрируется с системой непрерывного интегрирования, называемой CDash.
Заметка о TDD, многие люди рассматривают это как разработку, основанную на тестах, но это может быть Test Driven Design. Это очень хороший способ сосредоточиться на гибком дизайне, используя TDD для разработки моего программного обеспечения, а также для написания его действительно открыл глаза.
Ответ 12
Обычно я начинаю с чего-то более сложного, чем MinUnit, затем создайте набор макросов, который соответствует проекту, над которым я работаю в соответствии с этими проектными соглашениями.
Каждый компонент имеет исполняемый файл, который строит и запускает модульные тесты для этого компонента.
Я не использую отладчик, поскольку для этого требуется вмешательство человека, поэтому вы не можете использовать его для автоматической регрессии. Я не изменяю основной исполняемый файл, поскольку обычно он включает в себя множество компонентов и достаточно сложный, не имея большого количества макросов для включения и выключения битов. Создание новой цели с помощью make очень просто.