Как предотвратить qFatal () от прерывания приложения? - PullRequest
2 голосов
/ 30 апреля 2010

Мое приложение Qt использует Q_ASSERT_X, который вызывает qFatal (), который (по умолчанию) прерывает приложение. Это отлично подходит для приложения, но я хотел бы подавить такое поведение при модульном тестировании приложения. (Я использую Google Test Framework .) Я проводил юнит-тесты в отдельном проекте, статически связывая класс, который я тестирую. Документация для qFatal () гласит:

Вызывает обработчик сообщений с фатальное сообщение Если нет сообщения обработчик был установлен, сообщение распечатывается на stderr. Под Windows сообщение отправляется на отладчик.

Если вы используете сообщение по умолчанию обработчик, эта функция прервет Системы Unix для создания дампа ядра. На Windows, для отладочных сборок, это функция сообщит _CRT_ERROR позволяет подключить отладчик к приложение.

...

Чтобы подавить вывод во время выполнения, установите свой собственный обработчик сообщений с qInstallMsgHandler ().

Итак, вот мой файл main.cpp:

#include <gtest/gtest.h>
#include <QApplication>

void testMessageOutput(QtMsgType type, const char *msg) {
    switch (type) {
    case QtDebugMsg:
        fprintf(stderr, "Debug: %s\n", msg);
        break;
    case QtWarningMsg:
        fprintf(stderr, "Warning: %s\n", msg);
        break;
    case QtCriticalMsg:
        fprintf(stderr, "Critical: %s\n", msg);
        break;
    case QtFatalMsg:
        fprintf(stderr, "My Fatal: %s\n", msg);
        break;
    }
}

int main(int argc, char **argv)
{
    qInstallMsgHandler(testMessageOutput);
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

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

My Fatal: сбой ASSERT в MyClass :: doSomething: "doSomething ()", файл myclass.cpp, строка 21 Программа неожиданно закончил.

Что я могу сделать, чтобы мои тесты продолжали выполняться даже при сбое подтверждения?

Ответы [ 4 ]

4 голосов
/ 30 апреля 2010

Q_ASSERT_X ничего не компилируется при сборке релиза.

Итак, для модульного тестирования выполните сборку релиза, и она не будет вызывать qFatal.

2 голосов
/ 01 мая 2010

-DqFatal = qCritical:)

1 голос
/ 30 апреля 2010

По крайней мере для Qt-4.6.2, вы ничего не можете сделать.

src/corelib/global/qglobal.cpp определяет void qt_message_output(QtMsgType msgType, const char *buf), который сначала проверяет, установлен ли обработчик. Если это так, он вызывает его, в противном случае он использует обработчики по умолчанию. Сразу после этого он почти всегда прерывает (Unix / MingWn) или вызывает exit (другие).

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

0 голосов
/ 03 июня 2010

В некоторых случаях вы не можете превзойти qFatal и продолжать молча, протестированный компонент может находиться в таком состоянии, что сбой произойдет в любом случае после нескольких строк. Одним из способов избежать этого может быть заглушка qFatal где-нибудь в вашем тестовом коде;)

void qFatal(const char *msg, ...)
{
    QT_THROW(std::some_exception);
}

Тогда вы можете иметь собственный макрос assert:

#define CUSTOM_QEXPECT_FAIL( method ) { bool failed = false;\
    try { \
        method ; \
    }\
    catch(...) { \
        failed = true; \
    } \
    QVERIFY(failed); }

И используйте это в своем коде как:

CUSTOM_QEXPECT_FAIL( testedObj->panicAtTheDisco() );

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

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

...