189,67
рейтинг
31 декабря 2012 в 16:10

Разработка → Быстрый старт с Google Test


Google Test — это фреймворк от Google для юнит-тестирования кода на С++. Общей архитектурой он слегка напоминает общепринятые boost::test и CppUnit, хотя слегка отличается в деталях (как по мне — в лучшую сторону). Большая обзорная статья этого фреймворка уже как-то пробегала на Хабре, но нынче она в каком-то побитом состоянии (код не отображается), да и кажется мне слишком сложной для начала работы. Поэтому я коротко опишу «Hello world» на Google Test, указав на несколько потенциальных проблем, с которыми вы можете столкнуться, используя Google Test при разработке под Visual Studio.


Сборка


  1. Загружаем архив с кодом, разархивируем.
  2. В папке gtest-1.6.0\msvc есть два файла: gtest.sln и gtest-md.sln. Это файлы решений (Solution) Visual Studio. Отличаются они опциями сборки: gtest.sln собирает код с ключем /MT, а gtest-md.sln с ключем /MD. Если вы не знаете, за что отвечают эти ключи — можете почитать, к примеру, тут или тут. Вы должны скомпилировать тот же вариант, с которыми собирается проект, который вы собираетесь тестировать. Это важно, иначе получите кучу невразумительных ошибок линкера. Проверить, с какими ключами собирается ваш проект можно вот тут:



    Код Google Test успешно собирается Visual Studio 2008\2010 (другими не пробовал). На выходе вы получите файлы gtestd.lib\gtest.lib (для дебаг и релиз конфигураций). Со сборкой на этом всё.


Hello world


  1. Открываем Solution, который вы собираетесь тестировать. Добавляем в него новый проект (консольное С++ приложение).
  2. В этот проект добавляем зависимость от скомпиленных на втором шаге библиотек gtestd.lib\gtest.lib, путь к include-папке Google Test, зависимости к тем проектам в вашем решении, которые вы собираетесь тестировать.





  3. Пишем в главном файле тестового проекта следующий код:
    #include "stdafx.h"
    #include "gtest/gtest.h"
    
    class CRectTest : public ::testing::Test {
    };
    
    TEST_F(CRectTest, CheckPerimeter) 
    {
    	CSomeRect rect;
    	rect.x = 5;
    	rect.y = 6;
    	ASSERT_TRUE(rect.GetPerimeter() == 22);
    }
    
    int main(int argc, char **argv) {
    	::testing::InitGoogleTest(&argc, argv);
    	return RUN_ALL_TESTS();
    }
    


    Здесь мы тестируем некий класс прямоугольника на правильность вычисления периметра. Вы заметили, как удобненько — не нужно ни регистрировать каждый тест в main-функции, ни даже писать объявления тестовых методов в заголовочных файлах.

  4. Запускаем тестовый проект. Видим следующее:



Грабли


Номер один

Не ошибитесь с выбором компилируемого решения на втором шаге. Если ошибетесь и забудете — выяснить в чём ошибка позже будет фактически не реально.

Номер два

Если вы планируете разнести основное тестовое приложение и сами тесты по разным проектам, вы столкнётесь с одной хитрой проблемой. Дело в том, что гугловские юнит-тесы по сути являются статическими классами и компилятор Visual C++ из-за имеющегося нём бага попросту выкинет эти классы по ходу компиляции. Для избежания этого бага нужно выкрутиться способом, описанным вот тут.

Номер три

Не забывайте, что тестируемые статические библиотеки нужно не достаточно добавить в зависимости (Dependencies) тестового проекта, их нужно добавить в ссылки (References), иначе получим ошибки линковки.

Дополнительные материалы


Чуть более глубокая статья на Хабре
Быстрый старт в родной документации
Часто задаваемые вопросы
Продвинутое использование фреймворка
Плагин к Visual Studio для запуска тестов

Успехов в тестировании.
С Новым Годом!
Автор: @tangro

Комментарии (10)

  • +2
    Спасибо. Но если бы написали и о том, как использовать Gtest вне Visual Studio, поставил бы плюс.
    • 0
      Об использовании Gtest в linux (думаю, что применимо много где) и об автоматизации процесса тестирования: habrahabr.ru/post/133315/
      • 0
        Спасибо!
  • +5
    ASSERT_TRUE(rect.GetPerimeter() == 22);

    Такое лучше так писать:

    ASSERT_EQ(22, rect.GetPerimeter());
    • 0
      А чем лучше? Просто нагляднее или быстрее, или почему? Мне больше нравится везде писать ASSERT_TRUE — так не нужно запоминать все те три десятка макросов из GoogleTest и легко копировать\вставлять строки с тестами.
      • +2
        Сообщение о провалившемся тесте проще в восприятии. Сравните:

        //EXPECT_TRUE(1 == (1 - 1));
        Value of: 1 == (1 - 1)
          Actual: false
        Expected: true

        и

        //EXPECT_EQ(1, 1 - 1);
        Value of: 1 - 1
          Actual: 0
        Expected: 1
      • +1
        Потому что в твоем случае ты не увидишь значения getPerimiter, если ассерт зафейлится. И если для таких простых примеров это не критично, то для реальных тестов необходимость знать что за статус вернула функция или состояние принял объект — крайне важно для тестирования.
        • 0
          Мне как-то обычно хватает бинарного «тест прошел\тест зафейлился» — потому что если он зафейлился, в любом случае надо лезть разбираться, что бы там тест-кейс не выдал. Но ок, соглашусь, что это аргумент — действительно может помочь быстрее понять причину провала.
  • 0
    А вы с boost::test работали? Для начала было бы не плохо

    Общей архитектурой он слегка напоминает общепринятые boost::test и CppUnit, хотя слегка отличается в деталях (как по мне — в лучшую сторону)


    перечислить эти детали.

    Я работал с обоими, правда это было давно, но чем то мне gtest не понравился, и я помню что мы прям съезжали с gtest на boost. Вспомнить в чем были проблем щас уже не смогу, но вот если бы увидеть сравнительную статью этих двух фраемворков было бы очень здорово.

    Притом просто «hellow test» это не круто. Круто это когда вы смогли бы показать боле менее живой пример с сьюитами и кейсами, общими инициализационными классами, параметризацией выполнения, фильтрацией выхлопа…
    • +2
      Stackoverflow категорично в каждом буквально вопросе на эту тему склоняется к gtest: раз, два, три, четыре.

      Лично меня Гугл Тест подкупил необходимостью всего один раз объявить тест-кейс. В CppUnit, к примеру, это нужно сделать 3 раза: в заголовочном файле, в cpp-файле и при старте тестов.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка