Инструменты Open Spurce для модульного тестирования C/C++: Часть 2. Знакомство с CppUnit

Эта статья, вторая из серии статей об инструментах Open Source для модульного тестирования, познакомит вас с CppUnit – версией фреймворка JUnit, портированной на C++.

Арпан Сен, технический директор, Synapti Computer Aided Design Pvt Ltd

Арпан Сен (Arpan Sen) – ведущий инженер, работающий над разработкой программного обеспечения в области автоматизации электронного проектирования. На протяжении нескольких лет он работал над некоторыми функциями UNIX, в том числе Solaris, SunOS, HP-UX и IRIX, а также Linux и Microsoft Windows. Он проявляет живой интерес к методикам оптимизации производительности программного обеспечения, теории графов и параллельным вычислениям. Арпан является аспирантов в области программных систем.



13.01.2012

CppUnit – популярный фреймворк, являющийся портированной версией тестового фреймворка JUnit, написанного Эриком Гамма (Eric Gamma) и Кентом Беком (Kent Beck). Портированная на C++ версия была создана Майклом Фезерсом (Michael Feathers), и на ней основаны разнообразные классы, помогающие как при "тестировании белого ящика", так и при создании собственного пакета регрессионного тестирования. В этой статье рассмотрены наиболее полезные возможности CppUnit, такие как TestCase, TestSuite, TestFixture, TestRunner и вспомогательные макросы.

Часто используемые сокращения

  • GUI: Graphical user interface – графический пользовательский интерфейс.
  • XML: Extensible Markup Language – расширяемый язык разметки.

Загрузка и установка CppUnit

Для работы над этой статьей я загрузил и установил CppUnit на компьютере под управлением Linux® (версия ядра 2.4.21) с установленными утилитами g++-3.2.3 и make-3.79.1. Установка выполняется стандартно и заключается в последовательном запуске команд configure, make и make install. Обратите внимание на то, что во время установки на некоторые платформы, например cygwin, могут возникнуть определенные сложности, поэтому не забудьте заглянуть в документ INSTALL-unix, который является частью пакета установки. Если установка завершилась успешно, в установочной директории CppUnit (назовем ее CPPUNIT_HOME) вы должны увидеть поддиректории include и lib. Структура дерева папок показана в листинге 1.

Листинг 1. Структура установочной директории CppUnit
[arpan@tintin] echo $CPPUNIT_HOME
/home/arpan/ibm/cppUnit
[arpan@tintin] ls $CPPUNIT_HOME
bin  include  lib  man  share

Для компиляции теста, который использует CppUnit, необходимо скомпоновать исходный код:

g++ <C/C++ file> -I$CPPUNIT_HOME/include –L$CPPUNIT_HOME/lib -lcppunit

Обратите внимание на то, что если вы используете версию CppUnit с совместно используемыми библиотеками, для компиляции исходного кода может понадобиться использовать опцию –ldl. После установки также может потребоваться изменить переменную окружения UNIX® LD_LIBRARY_PATH в соответствии с местоположением библиотеки libcppunit.so.


Создание простого теста с помощью CppUnit

Лучшим способом изучения CppUnit является создание отдельного самостоятельного теста. В состав CppUnit входит множество предопределенных классов, которые оказываются очень полезными при разработке тестов. Давайте вспомним строковый класс, который мы рассматривали в первой части этой серии статей (листинг 2).

Листинг 2. Обычный строковый класс
#ifndef _MYSTRING
#define _MYSTRING

class mystring { 
  char* buffer; 
  int length;
  public: 
    void setbuffer(char* s) { buffer = s; length = strlen(s); } 
    char& operator[ ] (const int index) { return buffer[index]; }
    int size( ) { return length; }
 }; 

#endif

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

Листинг 3. Модульные тесты для строкового класса
#include <cppunit/TestCase.h>
#include <cppunit/ui/text/TextTestRunner.h>

class mystringTest : public CppUnit::TestCase {
public:

  void runTest() {
    mystring s;
    CPPUNIT_ASSERT_MESSAGE("String Length Non-Zero", s.size() != 0);
  }
};

int main ()
{
  mystringTest test;
  CppUnit::TextTestRunner runner;
  runner.addTest(&test);

  runner.run();
  return 0;
}

Первый класс базового кода CppUnit, с которым вы познакомитесь – это класс TestCase. Чтобы создать модульный тест для строкового класса, необходимо создать производный класс от CppUnit::TestCase и подменить метод runTest. Теперь, когда сам тест определен, присвойте нужные значения классу TextTestRunner, являющемуся неким управляющим классом, к которому необходимо добавлять отдельные тесты (см. метод addTest). Результаты выполнения метода run показаны в листинге 4.

Листинг 4. Результаты выполнения кода листинга 3
[arpan@tintin] ./a.out
!!!FAILURES!!!
Test Results:
Run:  1   Failures: 1   Errors: 0


1) test:  (F) line: 26 try.cc
assertion failed
- Expression: s.size() == 0
- String Length Non-Zero

Чтобы убедиться, что утверждение работает, инвертируйте условие в макросе CPPUNIT_ASSERT_MESSAGE. В листинге 5 показаны результаты выполнения кода при заданном условии s.size() ==0.

Листинг 5. Результаты выполнения кода листинга 3 при заданном условии s.size( ) == 0
[arpan@tintin] ./a.out

OK (1 tests)

Заметьте, что класс TestRunner не является единственным способом выполнения отдельного теста или тестового пакета. В CppUnit имеется альтернативная иерархия классов для запуска тестов, а именно шаблонизированный класс TestCaller. Вместо runTest для выполнения любого метода можно использовать класс TestCaller. Пример приведен в листинге 6.

Листинг 6. Использование класса TestCaller для запуска тестов
class ComplexNumberTest ... { 
  public: 
     void ComplexNumberTest::testEquality( ) { … } 
};

CppUnit::TestCaller<ComplexNumberTest> test( "testEquality", 
                                             &ComplexNumberTest::testEquality );
CppUnit::TestResult result;
test.run( &result );

В этом примере с помощью метода testEquality определен класс типа ComplexNumberText (для проверки равенства двух комплексных чисел). TestCaller шаблонизирован с этим классом, а затем, как и в случае с TestRunner, осуществляется вызов метода run для запуска теста. Однако использование класса TestCaller в варианте "как есть" не очень распространено: класс TextTestRunner автоматически обрабатывает вывод результатов. В случае использования класса TestCaller необходимо использовать отдельные классы для обработки вывода. В этой статье вы столкнетесь с этим позже, когда будете использовать класс TestCaller для определения пользовательского тестового пакета.


Использование утверждений

В состав CppUnit входят несколько процедур для наиболее часто используемых сценариев работы с утверждениями. Эти процедуры определены как публичные статические методы класса CppUnit::Asserter, определенного в заголовке Asserter.h. Также в заголовке TestAssert.h перечислены предопределенные макросы для большинства из этих классов. В листинге 7 показано, как определен макрос CPPUNIT_ASSERT_MESSAGE из листинга 2.

Листинг 7. Определение макроса CPPUNIT_ASSERT_MESSAGE
#define CPPUNIT_ASSERT_MESSAGE(message,condition)                          \
  ( CPPUNIT_NS::Asserter::failIf( !(condition),                            \
                                  CPPUNIT_NS::Message( "assertion failed", \
                                                       "Expression: "      \
                                                       #condition,         \
                                                       message ),          \
                                  CPPUNIT_SOURCELINE() ) )

Объявление метода failIf, на котором основано утверждение, представлено в листинге 8.

Листинг 8. Объявление метода failIf
struct Asserter
{
…
  static void CPPUNIT_API failIf( bool shouldFail,
                                  const Message &message,
                                  const SourceLine &sourceLine = SourceLine() );
…
}

Если условие в методе failIf принимает значение True, вызывается исключение. Происходит внутренняя обработка этого процесса методом run. Еще один интересный и полезный макрос – это макрос CPPUNIT_ASSERT_DOUBLES_EQUAL, выполняющий проверку равенства двух значений типа double с заданной точностью (|ожидаемое значение – фактическое значение| ≤ допустимая погрешность). Определение макроса представлено в листинге 9.

Листинг 9. Определение макроса CPPUNIT_ASSERT_DOUBLES_EQUAL
void CPPUNIT_API assertDoubleEquals( double expected,
                                     double actual,
                                     double delta,
                                     SourceLine sourceLine,
                                     const std::string &message );
#define CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,actual,delta)        \
  ( CPPUNIT_NS::assertDoubleEquals( (expected),            \
                                    (actual),              \
                                    (delta),               \
                                    CPPUNIT_SOURCELINE(),  \
                                    "" ) )

Протестируем строковый класс еще раз

Можно продолжить всестороннее тестирование класса mystring, добавляя дополнительные проверки внутри метода runTest. Однако за исключением простейших классов, такой быстрый подход может привести к неконтролируемым последствиям. В таких случаях необходимо создавать и использовать тестовые пакеты. Рассмотрим листинг 10, в котором создается тестовый пакет для строкового класса.

Листинг 10. Создание тестового пакета для строкового класса
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TextTestRunner.h>
#include <cppunit/extensions/HelperMacros.h>

class mystringTest : public CppUnit::TestCase {
public:
  void checkLength() {
    mystring s;
    CPPUNIT_ASSERT_MESSAGE("String Length Non-Zero", s.size() == 0);
  }

  void checkValue() {
    mystring s;
    s.setbuffer("hello world!\n");
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Corrupt String Data", s[0], 'w');
  }

  CPPUNIT_TEST_SUITE( mystringTest );
  CPPUNIT_TEST( checkLength );
  CPPUNIT_TEST( checkValue );
  CPPUNIT_TEST_SUITE_END();
};

Здесь все достаточно просто. Для определения тестового пакета используется макрос CPPUNIT_TEST_SUITE. Модульные тесты пакета формируются из отдельных методов, являющихся фрагментами класса mystringTest. Очень скоро мы ознакомимся с этими макросами и их содержимым, но сначала давайте рассмотрим клиентский код листинга 11, использующий этот тестовый пакет.

Листинг 11. Клиентский код, использующий тестовый пакет для класса mystring
CPPUNIT_TEST_SUITE_REGISTRATION ( mystringTest );

int main ()
{
  CppUnit::Test *test =
    CppUnit::TestFactoryRegistry::getRegistry().makeTest();
  CppUnit::TextTestRunner runner;
  runner.addTest(test);

  runner.run();
  return 0;
}

В листинге 12 показаны результаты выполнения кода листинга 11.

Листинг 12. Результаты выполнения кода листинга 10 и листинга 11
[arpan@tintin] ./a.out
!!!FAILURES!!!
Test Results:
Run:  2   Failures: 2   Errors: 0


1) test: mystringTest::checkLength (F) line: 26 str.cc
assertion failed
- Expression: s.size() == 0
- String Length Non-Zero


2) test: mystringTest::checkValue (F) line: 32 str.cc
equality assertion failed
- Expected: h
- Actual  : w
- Corrupt String Data

Макрос CPPUNIT_ASSERT_EQUAL_MESSAGE, определенный в заголовке TestAssert.h, проверяет, совпадают ли значения ожидаемого и фактического аргументов. В случае несовпадения выводится заранее заданное сообщение. Макрос CPPUNIT_TEST_SUITE, определенный в заголовке HelperMacros.h, упрощает процесс создания тестового пакета и добавляет в него отдельные тесты. Внутри создается шаблонизированный объект типа CppUnit::TestSuiteBuilderContext (это эквивалент тестового пакета в контексте CppUnit) и каждый вызов макроса CPPUNIT_TEST добавляет соответствующий метод класса в этот пакет. Излишне говорить о том, что этот метод класса выступает в качестве модульного теста для кода. Обратите внимание на порядок расположения макросов: для успешной компиляции кода отдельный макрос CPPUNIT_TEST должен располагаться между макросами CPPUNIT_TEST_SUITE и CPPUNIT_TEST_SUITE_END.


Объединение тестов

Со временем разработчики расширяют функционал приложения, что приводит к необходимости дальнейшего тестирования. Добавление тестов в существующий тестовый пакет со временем приводит к неудобствам, а инкрементный характер изменений, для которых в первую очередь разрабатывались тесты, исчезает. К счастью, в составе CppUnit имеется макрос CPPUNIT_TEST_SUB_SUITE, который можно использовать для расширения существующих тестовых пакетов. Использование этого макроса показано в листинге 13.

Листинг 13. Расширение тестовых пакетов
class mystringTestNew : public mystringTest {
public:
  CPPUNIT_TEST_SUB_SUITE (mystringTestNew, mystringTest);
  CPPUNIT_TEST( someMoreChecks );
  CPPUNIT_TEST_SUITE_END();

  void someMoreChecks() {
    std::cout << "Some more checks...\n";
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION ( mystringTestNew );

Обратите внимание на то, что новый класс mystringTestNew является производным от предыдущего класса myStringTest. Макрос CPPUNIT_TEST_SUB_SUITE принимает в качестве двух аргументов новый класс и его суперкласс. На стороне клиента вместо двух классов вы просто регистрируете новый класс – остальной синтаксис почти такой же, как и для создания тестовых пакетов.


Настройка тестов с использованием фикстур

Фикстура, или класс TestFixture в контексте CppUnit, предназначена для очистки процедур setup и exit в отдельных тестах. Чтобы использовать фикстуры, необходимо выполнить наследование тестовых классов из CppUnit::TestFixture и подменить предопределенные методы setUp и tearDown. Метод setUp вызывается перед началом выполнения модульного теста, а метод tearDown – после его завершения. В листинге 14 показано использование класса TestFixture.

Листинг 14. Создание тестового пакета с использованием тестовых фикстур
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TextTestRunner.h>
#include <cppunit/extensions/HelperMacros.h>

class mystringTest : public CppUnit::TestFixture {
public:
  void setUp() { 
     std::cout << “Do some initialization here…\n”;
  }

  void tearDown() { 
      std::cout << “Cleanup actions post test execution…\n”;
  }

  void checkLength() {
    mystring s;
    CPPUNIT_ASSERT_MESSAGE("String Length Non-Zero", s.size() == 0);
  }

  void checkValue() {
    mystring s;
    s.setbuffer("hello world!\n");
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Corrupt String Data", s[0], 'w');
  }

  CPPUNIT_TEST_SUITE( mystringTest );
  CPPUNIT_TEST( checkLength );
  CPPUNIT_TEST( checkValue );
  CPPUNIT_TEST_SUITE_END();
};

В листинге 15 показаны результаты выполнения кода листинга 14.

Листинг 15. Результаты выполнения кода листинга 14
[arpan@tintin] ./a.out
. Do some initialization here…
FCleanup actions post test execution…
. Do some initialization here…
FCleanup actions post test execution…

!!!FAILURES!!!
Test Results:
Run:  2   Failures: 2   Errors: 0


1) test: mystringTest::checkLength (F) line: 26 str.cc
assertion failed
- Expression: s.size() == 0
- String Length Non-Zero


2) test: mystringTest::checkValue (F) line: 32 str.cc
equality assertion failed
- Expected: h
- Actual  : w
- Corrupt String Data

Из последнего листинга видно, что сообщения процедур setup и teardown выводятся по одному разу за время выполнения модульного теста.


Создание тестовых пакетов без использования макросов

Можно создавать тестовые пакеты без использования каких-либо вспомогательных макросов. Хотя никаких особых преимуществ от использования того или иного стиля нет, написание кода без использования макросов упрощает его последующую отладку. Для создания тестового пакета, не содержащего макросов, создадим экземпляр класса CppUnit::TestSuite и добавим отдельные тесты в тестовый пакет. После этого мы передаем сам тестовый пакет в класс CppUnit::TextTestRunner перед вызовом метода run. Как видно из листинга 16, код на стороне клиента остается почти таким же.

Листинг 16. Создание тестового пакета без использования вспомогательных макросов
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;
}

Чтобы разобраться в работе листинга 16, необходимо рассмотреть два класса пространства имен CppUnit. Это классы TestSuite и TestCaller, объявленные в заголовках TestSuite.h и TestCaller.h, соответственно. При вызове процедуры runner.run()для каждого объекта TestCaller внутри CppUnit вызывается метод runTest, который в свою очередь вызывает ту процедуру, которая была передана в конструктор TestCaller<mystringTest>. Код листинга 17 (из исходников CppUnit) иллюстрирует то, как вызываются отдельные тесты каждого пакета.

Листинг 17. Вызовы отдельных тестов пакета
void
TestComposite::doRunChildTests( TestResult *controller )
{
  int childCount = getChildTestCount();
  for ( int index =0; index < childCount; ++index )
  {
    if ( controller->shouldStop() )
      break;

    getChildTestAt( index )->run( controller );
  }
}

Класс TestSuite является производным от класса CppUnit::TestComposite.

Указатели в CppUnit

Важно, чтобы тестовый пакет был объявлен в куче, поскольку CppUnit внутренне удаляет указатель TestSuite в деструкторе TestRunner. Такой подход может не являться лучшим решением, и необходимость его использования не указана в документации CppUnit.


Запуск нескольких тестовых пакетов

Можно создать несколько тестовых пакетов и запускать их одновременно с помощью объекта TextTestRunner. Для этого нужно просто создать каждый тестовый пакет, как это было сделано в листинге 16, и затем добавить тот же метод addTest в класс TextTestRunner, как показано в листинге 18.

Листинг 18. Запуск нескольких тестовых пакетов с использованием класса TextTestRunner
CppUnit::TestSuite* suite1 = new CppUnit::TestSuite("mystringTest");
suite1->addTest(…);
…
CppUnit::TestSuite* suite2 = new CppUnit::TestSuite("mymathTest");
…
suite2->addTest(…);
CppUnit::TextTestRunner runner;
runner.addTest(suite1);
runner.addTest(suite2);
…

Определение пользовательского формата вывода

До сих пор вывод результатов тестирования генерировался в соответствии с умолчаниями класса TextTestRunner. Тем не менее, CppUnit позволяет использовать пользовательский формат вывода. Для этого можно использовать класс CompilerOutputter, объявленный в заголовке CompilerOutputter.h. Помимо прочего, этот класс позволяет задавать формат вывода в виде "имя файла–номер строки". Также вы можете сохранять вывод непосредственно в файл, а не выводить его на экран. В листинге 19 приведен пример перенаправления вывода в файл. Обратите внимание на формат %p:%l: первая его часть обозначает путь к файлу, а вторая – номер строки. При использовании этого формата вывод будет выглядеть примерно так: /home/arpan/work/str.cc:26.

Листинг 19. Перенаправление вывода теста в log-файл с использованием заданного формата
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TextTestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/CompilerOutputter.h>

int main ()
{
  CppUnit::Test *test =
    CppUnit::TestFactoryRegistry::getRegistry().makeTest();
  CppUnit::TextTestRunner runner;
  runner.addTest(test);

  const std::string format("%p:%l");
  std::ofstream ofile;
  ofile.open("run.log");
  CppUnit::CompilerOutputter* outputter = new
    CppUnit::CompilerOutputter(&runner.result(), ofile);
  outputter->setLocationFormat(format);
  runner.setOutputter(outputter);

  runner.run();
  ofile.close();
  return 0;
}

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


Дополнительные пользовательские настройки: отслеживание времени выполнения тестов

До сих пор для запуска тестов по умолчанию использовался класс TextTestRunner. Схема была достаточно простой: создание экземпляра объекта типа TextTestRunner, добавление к нему тестов и процедуры outputter и вызов метода run. Давайте теперь пойдем в другом направлении, используя класс TestRunner (являющийся суперклассом для TextTestRunner) и новую категорию классов, принимающих информацию (listeners). Предположим, вы хотите узнать, сколько времени занимает выполнение каждого теста – обычная задача разработчиков, занимающихся оценкой производительности. Прежде чем двигаться дальше, взгляните на листинг 20, в котором используются три класса: TestRunner, TestResult и myListener, являющийся производным от класса TestListener. Здесь используется тот же класс mystringTest, что и в листинге 10.

Листинг 20. Знакомство с классом TestListener
class myListener : public CppUnit::TestListener {
public:
  void startTest(CppUnit::Test* test) {
    std::cout << "starting to measure time\n";
  }
  void endTest(CppUnit::Test* test) {
    std::cout << "done with measuring time\n";
  }
};

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));

  CppUnit::TestRunner runner;
  runner.addTest(suite);

  myListener listener;
  CppUnit::TestResult result;
  result.addListener(&listener);

  runner.run(result);
  return 0;
}

В листинге 21 показаны результаты выполнения кода листинга 20.

Листинг 21. Результаты выполнения кода листинга 20
	[arpan@tintin] ./a.out
starting to measure time
done with measuring time
starting to measure time
done with measuring time

Класс myListener является подклассом CppUnit::TestListener. Необходимо соответственно подменить методы startTest и endTest, которые должны выполняться перед началом и после окончания каждого теста. Можно легко расширить эти методы таким образом, чтобы они определяли время выполнения каждого теста. Так почему бы не добавить этот функционал в процедуры setup/teardown? Это можно было бы сделать, но в результате произошло бы дублирование кода в методах setup/teardown каждого тестового пакета.

Далее, взгляните на объект runner, являющийся экземпляром класса TestRunner, который, в свою очередь, принимает аргумент типа TestResult в метод run, и на объект listener, добавленный в класс TestResult.

Что же произошло с выводом результатов? После выполнения метода run класс TextTestRunner выводил много информации, однако TestRunner не делает этого. В этом случае потребуется использовать объект outputter, который отображает информацию, собранную с помощью объекта listener во время выполнения теста. В листинге 22 показаны изменения, которые необходимо внести в листинг 20.

Листинг 22. Добавление объекта outputter для отображения информации о результатах выполнения теста
runner.run(result);
CppUnit::CompilerOutputter outputter( &listener, std::cerr );
outputter.write();

Однако не торопитесь, поскольку этого тоже недостаточно для компиляции кода. Конструктор объекта CompilerOutputter ожидает объект типа TestResultCollector, а поскольку сам TestResultCollector является производным от класса TestListener (ссылку на подробную иерархию классов вы можете найти в разделе Ресурсы), все, что нужно сделать – это создать производный класс myListener из TestResultCollector, как показано в листинге 23.

Листинг 23. Наследование класса listener из TestResultCollector
class myListener : public CppUnit::TestResultCollector {
…
};

int main ()
{
  …

  myListener listener;
  CppUnit::TestResult result;
  result.addListener(&listener);

  runner.run(result);

  CppUnit::CompilerOutputter outputter( &listener, std::cerr );
  outputter.write();

  return 0;
}

Результаты выполнения кода показаны в листинге 24.

Листинг 24. Результаты выполнения кода листинга 23
[arpan@tintin] ./a.out
starting to measure time
done with measuring time
starting to measure time
done with measuring time
str.cc:31:Assertion
Test name: checkLength
assertion failed
- Expression: s.size() == 0
- String Length Non-Zero

str.cc:31:Assertion
Test name: checkValue
assertion failed
- Expression: s.size() == 0
- String Length Non-Zero

Failures !!!
Run: 0   Failure total: 2   Failures: 2   Errors: 0

Заключение

В этой статье были рассмотрены некоторые специальные классы фреймворка CppUnit: TestResult, TestListener, TestRunner, CompilerOutputter и другие классы. CppUnit, являющийся самостоятельным фреймворком для модульного тестирования, имеет гораздо больше возможностей. В CppUnit имеются классы для генерации вывода в XML-формате (XMLOutputter), выполнения тестов в графическом режиме (MFCTestRunner и QtTestRunner), а также модульный интерфейс (CppUnitTestPlugIn). Рекомендую прочесть документацию CppUnit, чтобы получить информацию об иерархии классов, а также ознакомиться с примерами, входящими в состав установки фреймворка.

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=785468
ArticleTitle=Инструменты Open Spurce для модульного тестирования C/C++: Часть 2. Знакомство с CppUnit
publish-date=01132012