QTest — модульное тестирование в Qt

Автор: | 20 июня, 2025

Введение

Разработка качественного программного обеспечения невозможна без тестирования. В рамках экосистемы Qt предлагается встроенная система модульного тестирования — QTestLib, также известная просто как QTest. Это мощный и легкий инструмент, позволяющий создавать юнит-тесты для C++-приложений, построенных с использованием Qt. Он интегрирован с Qt Creator и может использоваться с системами CI/CD.

В этой статье мы рассмотрим:

  • Что такое QTest и зачем он нужен.
  • Основы создания тестов.
  • Использование различных макросов.
  • Проверка GUI и событий.
  • Интеграция с CMake и qmake.
  • Практические советы и примеры.

Что такое QTestLib?

QTestLib — это фреймворк для модульного тестирования, входящий в стандартный комплект Qt. Он позволяет:

  • Писать автоматические тесты для функций и методов.
  • Выполнять параметризованные тесты.
  • Проверять корректность работы пользовательских интерфейсов.
  • Поддерживать отчёты в разных форматах (XML, Tap, TeamCity и др.).
  • Интегрироваться с системами сборки (qmake, CMake) и CI.

Структура тестов в QTest

Все тесты представляют собой обычные C++ классы, наследующиеся от QObject. Методы тестов — это слоты, которые запускаются фреймворком.

Минимальный пример:

#include <QtTest>

class TestMath : public QObject {
    Q_OBJECT

private slots:
    void testAddition();
};

void TestMath::testAddition() {
    QCOMPARE(2 + 2, 4);
}

QTEST_MAIN(TestMath)
  • QCOMPARE(actual, expected) — основной макрос для проверки.
  • QTEST_MAIN генерирует main() и запускает все слоты с тестами.
  • testAddition() — слот, запускаемый QTest.

Основные макросы QTest

МакросОписание
QCOMPARE(a, b)Проверяет, равны ли значения a и b.
QVERIFY(expr)Проверяет, истинно ли логическое выражение.
QFAIL(message)Немедленно проваливает тест.
QSKIP(message)Пропускает тест.
QTEST(actual, type)Проверяет значение переменной.

Параметризованные тесты

Вы можете задавать входные данные заранее и тестировать одну и ту же функцию с разными наборами:

class TestPower : public QObject {
    Q_OBJECT

private slots:
    void testPower_data();
    void testPower();
};

void TestPower::testPower_data() {
    QTest::addColumn<int>("base");
    QTest::addColumn<int>("exp");
    QTest::addColumn<int>("result");

    QTest::newRow("2^3") << 2 << 3 << 8;
    QTest::newRow("3^2") << 3 << 2 << 9;
}

void TestPower::testPower() {
    QFETCH(int, base);
    QFETCH(int, exp);
    QFETCH(int, result);
    QCOMPARE(pow(base, exp), result);
}

Тестирование GUI

QTest позволяет симулировать нажатия клавиш, щелчки мыши, перемещения и т.п.:

void TestGui::testButtonClick() {
    QPushButton button("Click me");
    QSignalSpy spy(&button, &QPushButton::clicked);

    QTest::mouseClick(&button, Qt::LeftButton);

    QCOMPARE(spy.count(), 1); // проверяем, что сигнал emitted
}

Полезные функции:

  • QTest::keyClick(widget, Qt::Key_A)
  • QTest::mouseClick(widget, Qt::LeftButton)
  • QTest::qWait(ms) — ожидание в миллисекундах.

Тестирование событий и сигналов

Для тестирования сигналов удобно использовать QSignalSpy:

QSignalSpy spy(myObject, SIGNAL(dataReady(int)));
emit myObject->dataReady(42);

QCOMPARE(spy.count(), 1);
QCOMPARE(spy.at(0).at(0).toInt(), 42);

Интеграция с qmake

Пример .pro файла:

TEMPLATE = app
TARGET = testmath
CONFIG += qt warn_on console testcase

SOURCES += testmath.cpp

Запуск и формат вывода

QTest поддерживает разные форматы вывода:

./testapp -txt      # обычный текст
./testapp -xml      # XML, удобно для CI
./testapp -tap      # Test Anything Protocol

Для фильтрации тестов:

./testapp -functions       # список тестов
./testapp -functions | grep login
./testapp testAddition     # запуск одного теста

Практические советы

  • Разделяйте тесты по модулям: один класс — один модуль.
  • Используйте QSignalSpy для проверки сигналов.
  • Не тестируйте сразу много логики в одном тесте.
  • Используйте CI-системы для автоматизации (например, GitHub Actions, GitLab CI).

Плюсы QTest

✅ Интеграция с Qt и Qt Creator
✅ Простая и понятная структура
✅ Поддержка GUI и событий
✅ Легко встраивается в существующий проект
✅ Поддержка автоматических отчётов


Минусы QTest

❌ Не поддерживает BDD-подход (как GTest с GMock)
❌ Не самый удобный формат вывода без дополнительной обработки
❌ Ограниченный инструментарий моков (требуется реализация вручную)


Заключение

QTest — это мощный и гибкий инструмент, идеально подходящий для юнит-тестирования Qt-приложений. Он интегрирован с экосистемой Qt, прост в использовании и может применяться как для логических тестов, так и для тестирования интерфейсов.