Тестирование с помощью модуля Qt QTestLib - PullRequest
12 голосов
/ 01 мая 2010

Я начал писать некоторые тесты с системой модульного тестирования Qt.

Как вы обычно организуете тесты? Это один тестовый класс на один класс модуля, или вы тестируете весь модуль одним тестовым классом? Qt docs предлагает следовать прежней стратегии.

Я хочу написать тесты для модуля. Модуль предоставляет только один класс, который будет использоваться пользователем модуля, но есть много логики, абстрагированной в других классах, которую я также хотел бы проверить, помимо тестирования открытого класса.

Проблема в том, что предложенный Qt способ запуска тестов включал макрос QTEST_MAIN:

QTEST_MAIN(TestClass)
#include "test_class.moc"

и в итоге одна тестовая программа способна протестировать только один тестовый класс. И это отстойно - создавать тестовые проекты для каждого класса в модуле.

Конечно, можно посмотреть макрос QTEST_MAIN, переписать его и запустить другие тестовые классы. Но есть ли что-то, что работает из коробки?

Пока я делаю это вручную:

#include "one.h"
#include "two.h"

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 
    TestOne one;
    QTest::qExec(&one, argc, argv);
    TestOne two;
    QTest::qExec(&two, argc, argv);
}

Ответы [ 4 ]

6 голосов
/ 29 июня 2014

Относится к ответу @ cjhuitt

Это пример, который устраняет необходимость вручную вызывать каждый тестовый объект

Я стараюсь избегать вещей, подобных этому:

MyTestClass1 t1;   t1.run();
MyTestClass2 t2;   t2.run();
//etc...

Мое решение - позволить тестовым объектам наследовать от базового класса, который добавляет себя в статический список Затем основная программа выполняет все тестовые объекты в этом списке. Таким образом, ни один из кодов вспомогательной платформы не нужно менять. Меняются только сами тестовые классы.

Вот как я это делаю:

qtestsuite.h - базовый класс для тестовых объектов

#ifndef QTESTSUITE_H
#define QTESTSUITE_H

#include <QObject>
#include <vector>

class QTestSuite : public QObject
{
    Q_OBJECT
public:
    static std::vector<QObject*> m_suites;

public:
    explicit QTestSuite();

};

#endif // QTESTSUITE_H

qtestsuite.cpp

#include "qtestsuite.h"
#include <iostream>

std::vector<QObject*> QTestSuite::m_suites;

QTestSuite::QTestSuite() : QObject()
{
    m_suites.push_back(this);
}

testall.cpp - запускает тесты

#include "qtestsuite.h"

#include <QtTest/QtTest>
#include <iostream>

int main(int, char**)
{
    int failedSuitesCount = 0;
    std::vector<QObject*>::iterator iSuite;
    for (iSuite = QTestSuite::m_suites.begin(); iSuite != QTestSuite::m_suites.end(); iSuite++)
    {
        int result = QTest::qExec(*iSuite);
        if (result != 0)
        {
            failedSuitesCount++;
        }
    }
    return failedSuitesCount;
}

mytestsuite1.cpp - пример тестового объекта, создайте больше таких

#include "qtestsuite.h"

#include <QtTest/QtTest>

class MyTestSuite1: public QTestSuite
{
     Q_OBJECT
private slots:
    void aTestFunction();
    void anotherTestFunction();
};

void MyTestSuite1::aTestFunction()
{
    QString str = "Hello";
    QVERIFY(str.toUpper() == "this will fail");
}

void MyTestSuite1::anotherTestFunction()
{
    QString str = "Goodbye";
    QVERIFY(str.toUpper() == "GOODBYE");
}

static MyTestSuite1 instance;  //This is where this particular test is instantiated, and thus added to the static list of test suites

#include "mytestsuite1.moc"

также для создания .pro-файла

qmake -project "CONFIG += qtestlib"
5 голосов
/ 03 мая 2010

В нашей установке с QTest мы сделали несколько вещей, чтобы сделать его лучше.

  • Определить подкласс QObject, который используется в качестве базового класса для любого нового класса модульного теста.
  • В конструкторе для этого класса мы добавляем экземпляр теста в статический список тестов, а в деструкторе - удаляем его.
  • Затем у нас есть статическая функция, которая перебирает тесты и запускает их, используя QTest::qExec(). (Мы накапливаем значения, возвращаемые каждый раз, и возвращаем их из нашей функции.)
  • main() вызывает эту функцию и возвращает результат как успех / неудача.
  • Наконец, в модуле компиляции конкретного теста мы обычно включаем статический экземпляр этого класса.

Эта настройка означает, что экземпляр класса будет создан до запуска main(), поэтому он будет добавлен в список классов для проверки при выполнении основных операций. Фреймворк требует, чтобы вам просто нужно было правильно наследовать ваш класс и создавать экземпляр статического экземпляра, если вы всегда хотите, чтобы он запускался.

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

4 голосов
/ 02 мая 2010

Да, QTest заставляет немного странную структуру теста и, как правило, уступает Google Test / Mock Framework. Для одного проекта я вынужден использовать QTest (требование клиента), и вот как я его использую:

  1. Я собираю все тесты вместе как шаблон проекта subdir
  2. Чтобы упростить создание новых тестов, я совместно использую конфигурацию проекта, используя файл common.pri, который я включаю в каждый тестовый файл .pro
  3. Если возможно, я делюсь каталогом объектных файлов для ускорения компиляции
  4. Я запускаю их все, используя пакетный + awk + sed скрипт.

Настройка этих четырех пунктов очень проста и делает использование QTest практически приятным. Есть ли у вас проблемы с запуском нескольких тестов, которые не решаются с помощью описанной выше конфигурации?

PS: выполнение тестов так, как вы делаете, то есть вызов нескольких QTest :: qExec вызывает проблемы с ключом командной строки -o - вы получите результаты только для последнего протестированного класса.

0 голосов
/ 05 марта 2011

Обычно я организую тесты по одному исполняемому файлу на каждый тестируемый класс.

и в конечном итоге одна тестовая программа способен тестировать только один тест класс.

Это хорошо. Он изолирует ваши тесты друг от друга, предотвращая блокировку всех других тестов такими вещами, как сбой в одном тесте. Этот сбой может быть вызван общим компонентом в нескольких тестируемых классах. Схема сбоев будет указывать вам на причину возникновения проблемы. По сути, у вас есть лучшая диагностическая информация о сбоях, если ваши тесты не зависят друг от друга.

Позволяет легко настроить несколько исполняемых файлов и запускать каждый тест отдельно. Используйте тестового бегуна для запуска всех процессов тестирования.

Обновление:

Я несколько передумал. Когда у вас есть большая программа с большим количеством тестов, связывание сотен исполняемых файлов теста становится очень медленным. Мое новое предпочтение - поместить все тесты для библиотеки в исполняемый файл и выбирать, какие тесты вызывать с использованием аргументов командной строки, передаваемых в исполняемый файл теста.

Это сокращает количество исполняемых файлов с сотен до десятков, но сохраняет преимущества запуска тестов по отдельности.

...