Тестирование с использованием Google Test

Материал из Викиконспекты
Версия от 19:33, 4 сентября 2022; Maintenance script (обсуждение | вклад) (rollbackEdits.php mass rollback)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Задача

Дан линейный порядок и два элемента. Необходимо перечислить элементы линейного порядка, которые находятся между данными, и протестировать решение на правильность и скорость.

Решение

Напишем функцию intersect, которая решает задачу поиска и перечисления с помощью эффективного алгоритма. Также напишем intersect_slow (для удобства — с той же сигнатурой), которая решает ту же задачу медленно, но достоверно.

Пишем два теста: на правильность и на скорость. В обоих генерируется вектор из случайных чисел, на котором запускаются обе функции. В первом случае результаты проверяются на равенство. Во втором подсчитываем время, затраченное обоими алгоритмами, и проверяем, быстрее ли наш эффективный алгоритм.

Реализация

Тестирование будет проводиться в main.cpp.

Подключение gtest к проекту

Добавим в CMakeLists.txt строчку

find_package(GTest)

и изменим строчку target_link_libraries, добавив туда ${GTEST_LIBRARY}, например:

target_link_libraries(${PROJECT\_NAME} ${GTEST_LIBRARY})

В main.cpp делаем

#include <gtest/gtest.h>.

Функция main()

Она будет выглядеть так:

int main(int argc, char ** argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Первая строчка позволяет колдовать с разными флагами тестирования. RUN_ALL_TESTS() обязательно должен запускаться ровно один раз, а main должна возвращать его значение.

Собственно тест

Тесты выглядят так:

TEST(test_case_name, test_name)
{
    ... test body ...
}

test_case_name — имя тесткейза, test_name — имя теста внутри этого тесткейза. У разных тесткейзов могут быть тесты с одинаковыми именами, ибо полное имя теста составляется из обоих этих имён. Эти имена должны быть валидными плюсовыми идентификаторами. Утверждается, что они не должны содержать в себе подчёркиваний, но с ними всё отлично работает.

Собственно тестирование заключается в вызове, например, EXPECT_EQ(val1, val2), которое проверяет val1 и val2 на равенство. В случае, если они не равны, в выводе будет написано, что случился фейл в таком-то тесте и будут выведены значения val1 и val2. Также бывают EXPECT_LE (проверяет, что val1 <= val2), EXPECT_LT (val1 < val2) и т.д.

Кстати, тесты можно отключать: необходимо исправить test_name на DISABLED_test_name. Тогда этот тест не будет запускаться, а gtest сообщит о том, что имеются отключённые тесты.

Собственно реализация

https://github.com/katyatitkova/intersect_test

Кажущиеся проблемы нашего решения

Каждый тест запускается только один раз, нам этого недостаточно

Вспомним про флаги тестирования, посмотрим в справку по ним:

./intersect --help

(запускать в папке сборки). В частности, узнаем, что флаг --gtest_repeat=[COUNT] решает нашу проблему. Чтобы запуститься с этим флагом, набираем в консоли во всё той же папке сборки, например

./intersect --gtest_repeat=10

А мы вообще сможем повторно запуститься на тех же тестах, на которых завалились? Рандом всё-таки

Да, сгенерённые числа в каждом запуске будут одинаковыми. То есть, если мы вызовем ./intersect --gtest_repeat=10, каждый из этих 10 раз будет разным, но следующий запуск ./intersect --gtest_repeat=10 сгенерирует то же самое, что было в прошлый раз. (Подсказывают, что этот эффект достигается за счёт использования std::default_random_engine)