Что новенького?
Одна из главных новых возможностей - это "The event listener API". А попросту говоря, возможность полностью контролировать процесс печати результатов тестирования. Это позволяет формировать отчеты по тестированию в нужном формате без изменения кода библиотеки.
Например, стандартный вывод при выполнении элементарного теста (файл
runner.cpp
):#include "gtest/gtest.h"
TEST(One, Simple) {
EXPECT_EQ(1, 2);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
будет таким:[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from One
[ RUN ] One.Simple
runner.cpp(4): error: Value of: 2
Expected: 1
[ FAILED ] One.Simple (15 ms)
[----------] 1 test from One (15 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (31 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] One.Simple
1 FAILED TEST
Для задания иного формата вывода нужно реализовать свой event listener
(назовем его сервис печати
). Например (файл runner.cpp
):#include "gtest/gtest.h"
using namespace ::testing;
// Данный класс заменит стандартный сервис печати.
class LaconicPrinter : public ::testing::EmptyTestEventListener {
// Вызывается до начала работы теста.
virtual void OnTestStart(const TestInfo& test_info) {
printf("*** Test %s.%s starting.\n",
test_info.test_case_name(), test_info.name());
}
// Вызывается при срабатывании какого-либо утверждения или явного вызова
// функции SUCCESS().
virtual void OnTestPartResult(const TestPartResult& test_part_result) {
printf("%s in %s:%d\n%s\n",
test_part_result.failed() ? "*** Failure" : "Success",
test_part_result.file_name(),
test_part_result.line_number(),
test_part_result.summary());
}
// Вызывается после выполнения теста.
virtual void OnTestEnd(const TestInfo& test_info) {
printf("*** Test %s.%s ending.\n",
test_info.test_case_name(), test_info.name());
}
};
TEST(One, Simple) {
EXPECT_EQ(1, 2);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
// Получаем ссылку на список сервисов печати.
::testing::TestEventListeners& listeners =
::testing::UnitTest::GetInstance()->listeners();
// Удаляем стандартный сервис печати.
delete listeners.Release(listeners.default_result_printer());
// Добавляем наш сервис в список. Google Test самостоятельно удалит этот объект.
listeners.Append(new LaconicPrinter);
return RUN_ALL_TESTS();
}
Теперь отчет по работе тестов будет выглядеть так:*** Test One.Simple starting.
*** Failure in runner.cpp:31
Value of: 2
Expected: 1
*** Test One.Simple ending.
Необходимо отметить, что одновременно может быть зарегистрировано несколько сервисов печати. Но в этом случае их выводы могут смешиваться и превращаться в кашу. Для избежания этого мы принудительно удаляем стандартный сервис печати, чтобы его вывод не мешал нашему.Полностью интерфейс сервиса печати выглядит так:
class EmptyTestEventListener : public TestEventListener {
public:
// Вызывается при начале прогона всех тестов.
virtual void OnTestProgramStart(const UnitTest& unit_test);
// Вызывается при начале очередной итерации тестирования. Google Test
// позволяет управлять количеством итерации при прогоне тестов.
virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
// Вызывается до функции Environment::SetUp(), устанавливающей необходимое
// окружение для работы всех тестов.
virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
// Вызывается после функции Environment::SetUp(), устанавливающей необходимое
// окружение для работы всех тестов.
virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
// Вызывается при начале прогона группы тестов (у которых первый параметр
// макроса TEST/TEST_F одинаковый).
virtual void OnTestCaseStart(const TestCase& test_case);
// Вызывается при начале работы теста.
virtual void OnTestStart(const TestInfo& test_info);
// Вызывается при срабатывании утверждения в тесте или явного вызова
// функции SUCCESS().
virtual void OnTestPartResult(const TestPartResult& test_part_result);
// Вызывается после завершения работы теста.
virtual void OnTestEnd(const TestInfo& test_info);
// Вызывается после прогона группы тестов.
virtual void OnTestCaseEnd(const TestCase& test_case);
// Вызывается до функции Environment::TearDown(), производящей освобождение
// ресурсов, занятых Environment::StartUp().
virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
// Вызывается после функции Environment::TearDown().
virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
// Вызывается после очередной итерации тестирования.
virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
// Вызывается после прогона всех тестов.
virtual void OnTestProgramEnd(const UnitTest& unit_test);
};
Также из значимого можно отметить новый ключ командной строки --gtest_shuffle
, позволяющий запускать тесты в случайном порядке. Ключом --gtest_random_seed=SEED
можно "управлять" случайностью этого порядка. Если SEED
равен 0
, то случайность будет действительно случайной, так как случайная последовательность будет определяться текущим временем.Что приятно, теперь формат XML файлов, генерируемых при использовании ключа
--gtest_output
, полностью совместим с форматом JUnit. Это значит, что, например, система автоматической сборки, тестирования и интеграции Hudson теперь понимает отчеты Google Test без дополнительный конвертации.Также теперь при работе в Visual Studio сообщения о сбойных тестах выводятся прямо в окно "Output", что позволяет, кликая на них, сразу находить строки, где сбоят тесты. Здорово, что данная фича основана на моем коде.
Еще, теперь время работы тестов печатается всегда, по умолчанию, то есть опция
--gtest_print_time
будто бы всегда включена.Есть еще несколько незначительных улучшений:
- поддержка CodeGear Studio
- собственная реализация
tuple
для независимости отboost
при использованииCombine()
- множество улучшений для совместимости с Solaris, Windows Mobile и некоторыми другими платформами.
Я перестал что-то писать что-либо на C++ без тестов, а Google Test делает этот процесс простым и легким.
Я уже обновился до версии 1.4.0, а вы?
Ссылки по теме:
- Документация Google Test на русском языке
- Что нового в Google Test 1.3.0
Даже и не знал о существовании такого фреймворка. Спасибо за наводку =)
ОтветитьУдалитьЧестно говоря, с чисто прагматичной точки зрения, я не встречал более удобной библиотеки.
ОтветитьУдалитьА чем Google C++ Testing Framework отличается от CppUnit?
ОтветитьУдалить>> Здорово, что данная фича основана на моем коде.
ОтветитьУдалитьЗабавно - я тоже делал такой же патч :) Выбрали твой?
White Knight: Навскидку, при использовании CppUnit мне приходилось каждый тест прописывать в головном .h файле как функцию-член test fixture. Что очень раздражало. Может сейчас уже этого нет, я не в курсе. В GTest просто пишешь тест через TEST() или TEST_F() и все. Удобно при перетаскивании тестов из модуля в модуль.
ОтветитьУдалитьА еще в GTest очень удобно печатать трассировочные данные при сбое теста, так как в любую функцию-assert можно писать как в поток через <<. И это будет печататься, если assert сбоит, например:
EXPECT_TRUE(some_object.some_function()) << "Блин! тут сбой, а some_object.i = " << some_object.i;
и т.д.
bishop: Выходит, что так ;-)
ОтветитьУдалитьКак сделать так, чтоб русский текст правильно отображался одновременно в консоле и XML отчете?
ОтветитьУдалитьХм, удивляюсь, почему там вообще используется русский текст. А в какой кодировке русский в XMLe? Может изменить кодировку консоли сообразно?
ОтветитьУдалитьНу русский текст я сам использую в отчете для удобства. Проект юникодный, консоль - всегда OEM, к сожалению. А ф-ции типа wprintf работают только за счёт преобразований. Удалось добиться желаемого путём настройки консоли и xml файла (просто заменив encoding=) на кодировку 1251. Но с версией 1.4.0 в xml файле русский текст больше не отображается таким способом. Видимо это была ошибка, которую уже исправили.
ОтветитьУдалитьВ общем пришлось убрать преобразование в UTF-8
ОтветитьУдалитьА вы напишите подробнее про Google C++ Mocking Framework ?
ОтветитьУдалитьКак в GTF можно подключить систему тестирования к разработке отдельных библиотек (*.dll) ?
ОтветитьУдалитьАртур, а что конкретно нужно?
ОтветитьУдалитьФреймворк хороший, вот только не получается заставить его работать на AIX 5.2. После небольших изменений скомпилировал, но работать он не хочет...
ОтветитьУдалитьK01egA: Какие именно проблемы? Я использую это на Linux, Solaris Sparc, HP-UX v3, AIX 5.2, 5.3 and 6.0. Вроде проблемы были только на старом компиляторе HP-UX v2. На v3 все хорошо.
ОтветитьУдалитькомпилятор VisualAge C++ 6, для начала пропатчил gtest-port.h аналогично http://groups.google.com/group/googletestframework/msg/9431cd036422ef99 для версии 1.3, потом компилятор отказывался понимать
ОтветитьУдалитьtemplate typename T
static void Delete(T * x) {
delete x;
}
заменил на
template typename T
struct Delete {
void operator()(T * x)
{
delete x;
}
};
скопмилиовал, но любой тест падает в кору из-за того что GTEST_FLAG(internal_run_death_test) не инициализируется пустой строкой, GTEST_FLAG(internal_run_death_test) == NULL.
Все глобальные переменные которые инициализируются функцией или конструктором имеют нулевое значение, функция инициализации похоже вообще не вызывается.
Наверное никто не пользуется уже такими древними компиляторами, но политика партии не позволяет использовать другой.
У меня на AIX стоит:
ОтветитьУдалить$ xlc -qversion
IBM XL C/C++ Enterprise Edition V8.0 for AIX
Version: 08.00.0000.0020
А на AIX 6.1 -- v10.1.
Так что про шестерку ничего не скажу. У AIX вообще полно приколов со статическими объектами, но у меня как-то все работает. Может шестерка дествительно может чего-то не понимать.
Что ж прийдется использовать CppUnit он хоть и не такой удобный но работает без проблем.
ОтветитьУдалить