Тестирование с модулем QT Qtestlib
-
02-10-2019 - |
Вопрос
Я начал писать некоторые тесты с системой модульного тестирования QT.
Как вы обычно организуете тесты? Это один тестовый класс на один класс модуля, или вы тестируете весь модуль с одним тестовым классом? Документы QT предлагают следовать прежней стратегии.
Я хочу написать тесты для модуля. Модуль предоставляет только один класс, который будет использоваться пользователем модуля, но в других классах есть много логики, которую я также хотел бы протестировать, помимо тестирования публичного класса.
Проблема в том, что предложенный 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);
}
Решение
Да, Qtest Sight Bit Strange Test Structure и, как правило, уступает Google Test/Mock Framework. Для одного проекта я вынужден использовать QTEST (требование клиента), и вот как я его использую:
- Я собираю все тестирование вместе как шаблонный проект поддира
- Чтобы упростить создание новых тестов, я поделюсь много конфигурации проекта, используя файл common.pri, который я включаю в каждый тест .pro.
- Если возможно, я делюсь каталогом объектных файлов, чтобы ускорить компиляцию
- Я запускаю их всех, используя сценарий пакета+AWK+SED.
Настройка этих четырех точек очень проста и делает использование QTest почти приятным. У вас есть некоторые проблемы с запуском нескольких тестов, которые не решаются конфигурацией, описанной выше?
PS: Запуск тестов так, как вы делаете, то есть вызывая несколько QTest :: Qexec вызывает проблемы с коммутатором -O командной строки - вы получите только результаты для последнего тестируемого класса.
Другие советы
Связано с ответом, опубликованным @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"
В нашей настройке с QTest мы сделали несколько вещей, чтобы сделать это лучше.
- Определите подкласс QObject, который используется в качестве базового класса для любого нового класса единиц.
- В конструкторе для этого класса мы добавляем экземпляр теста в статический список тестов, а в деструкторе мы его удаляем.
- Затем у нас есть статическая функция, которая проходит через тесты и запускает их, используя
QTest::qExec()
. Анкет (Мы накапливаем значения, возвращаемые каждый раз, и возвращаем это из нашей функции.) main()
вызывает эту функцию и возвращает результат как успех/неудачу.- Наконец, в единицу компиляции самого конкретного теста мы обычно включаем статический экземпляр этого класса.
Эта настройка означает, что класс будет создан ранее main()
запускается, поэтому он будет добавлен в список классов для тестирования при основных запусках. Структура требует, чтобы вам просто нужно было правильно унаследовать свой класс и создавать статический экземпляр, если вы всегда хотите, чтобы он работал.
Мы также иногда создаем другие дополнительные тесты, которые добавляются на основе коммутаторов командной строки.
Обычно я организую тесты с одним тестируемым выполнением на тестирование на класс.
И в конечном итоге одна тестовая программа способна тестировать только один тестовый класс.
Это хорошая вещь. Он изолирует ваши тесты друг от друга, предотвращая такие вещи, как сбой в одном тесте, блокировать все другие ваши тесты. Этот аварий может быть вызван общим компонентом в нескольких тестовых классах. Образец сбоев затем подтолкнет вас к основному происхождению проблемы. По сути, у вас есть лучшая диагностическая информация для сбоев, если ваши тесты не зависят друг от друга.
Сделайте это легко настроить несколько исполняемых файлов и запустить каждый тест отдельно. Используйте тестовый бегун, чтобы вырестить все процессы тестирования.
Обновлять:
Я передумал на это. После того, как у вас есть большая программа с большим количеством тестов, связывание сотен исполняемых файлов станет очень медленным. Мое новое предпочтение состоит в том, чтобы разместить все тесты для библиотеки в исполняемый файл и выбрать, какие тесты вызывают с использованием аргументов командной строки, передаваемых тестируемому исполнению.
Это сокращает количество исполняемых файлов с сотен до десятков, но сохраняет преимущества проведения тестов отдельно.