Вопрос

Я начал писать некоторые тесты с системой модульного тестирования 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 (требование клиента), и вот как я его использую:

  1. Я собираю все тестирование вместе как шаблонный проект поддира
  2. Чтобы упростить создание новых тестов, я поделюсь много конфигурации проекта, используя файл common.pri, который я включаю в каждый тест .pro.
  3. Если возможно, я делюсь каталогом объектных файлов, чтобы ускорить компиляцию
  4. Я запускаю их всех, используя сценарий пакета+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() запускается, поэтому он будет добавлен в список классов для тестирования при основных запусках. Структура требует, чтобы вам просто нужно было правильно унаследовать свой класс и создавать статический экземпляр, если вы всегда хотите, чтобы он работал.

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

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

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

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

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

Обновлять:

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top