Как я могу немедленно провалить автотест, если появится предупреждение

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

Я подумал, что могу использовать qInstallMessageHandler() для этого. Я изменил пример из здесь:

#include <QtTest>

class AutoTest : public QObject
{
    Q_OBJECT

public:
    AutoTest();
    ~AutoTest();

private slots:
    void test_case1();

};

void warningMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    const char *file = context.file ? context.file : "";
    const char *function = context.function ? context.function : "";
    switch (type) {
    case QtDebugMsg:
        fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    case QtInfoMsg:
        fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    case QtWarningMsg:
        fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        exit(1);
    case QtCriticalMsg:
        fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    case QtFatalMsg:
        fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    }
}

AutoTest::AutoTest()
{
    qInstallMessageHandler(warningMessageHandler);
}

AutoTest::~AutoTest()
{

}

void AutoTest::test_case1()
{
    qWarning() << "This should cause the application to exit with code 1";
}

QTEST_APPLESS_MAIN(AutoTest)

#include "tst_autotest.moc"

Однако тестовое приложение не закрывается раньше, чем ожидалось:

17:32:04: Starting /Users/mitch/dev/temp/autotest-qt5_14_fw-Debug/autotest.app/Contents/MacOS/autotest ...
********* Start testing of AutoTest *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 10.0.0 (clang-1000.11.45.2) (Apple))
PASS   : AutoTest::initTestCase()
QWARN  : AutoTest::test_case1() This should cause the application to exit
PASS   : AutoTest::test_case1()
PASS   : AutoTest::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 2ms
********* Finished testing of AutoTest *********
17:32:04: /Users/mitch/dev/temp/autotest-qt5_14_fw-Debug/autotest.app/Contents/MacOS/autotest exited with code 0

Я поставил точку останова в функции обработчика сообщений, и она не сработала ни разу. В чем дело?


person Mitch    schedule 28.11.2019    source источник


Ответы (1)


Хотя пример в документации показывает, что обработчик устанавливается в начале main(), этого недостаточно для автотеста. Похоже, что есть и другие обработчики сообщений, которые сам Qt устанавливает во время жизни автотеста, и они устанавливаются немного позже, чем конструктор теста. Вы можете убедиться в этом сами, если собирали Qt из исходников, поставив точку останова здесь.

Инфраструктура протоколирования тестов Qt устанавливает свой собственный обработчик сообщений сразу после создания самого теста (внутри макроса QTEST_APPLESS_MAIN).

Если вы используете отладку QML в Creator, то также будет установлен собственный обработчик сообщений.

Чтобы обойти это, установите обработчик как можно позже:

#include <QtTest>

class AutoTest : public QObject
{
    Q_OBJECT

public:
    AutoTest();
    ~AutoTest();

private slots:
    void initTestCase();
    void test_case1();

};

static QtMessageHandler oldMessageHandler;

// Exits on warnings
void warningMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    const char *file = context.file ? context.file : "";
    const char *function = context.function ? context.function : "";
    switch (type) {
    case QtWarningMsg:
        fprintf(stderr, "EXITING - TEST FAILED DUE TO WARNING: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        exit(1);
    default:
        oldMessageHandler(type, context, msg);
    }
}

AutoTest::AutoTest()
{
}

AutoTest::~AutoTest()
{

}

void AutoTest::initTestCase()
{
    oldMessageHandler = qInstallMessageHandler(warningMessageHandler);
}

void AutoTest::test_case1()
{
    qWarning() << "This should cause the application to exit with code 1";
}

QTEST_APPLESS_MAIN(AutoTest)

#include "tst_autotest.moc"

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

Это выводит:

17:44:44: Starting /Users/mitch/dev/temp/autotest-qt5_14_fw-Debug/autotest.app/Contents/MacOS/autotest ...
********* Start testing of AutoTest *********
Config: Using QtTest library 5.14.0, Qt 5.14.0 (x86_64-little_endian-lp64 shared (dynamic) debug build; by Clang 10.0.0 (clang-1000.11.45.2) (Apple))
EXITING - TEST FAILED DUE TO WARNING: This should cause the application to exit with code 1 (../autotest/tst_autotest.cpp:50, void AutoTest::test_case1())
PASS   : AutoTest::initTestCase()
17:44:44: /Users/mitch/dev/temp/autotest-qt5_14_fw-Debug/autotest.app/Contents/MacOS/autotest exited with code 1
person Mitch    schedule 28.11.2019