如何防止 qFatal() 中止应用程序?

发布于 2024-08-30 13:31:48 字数 1555 浏览 8 评论 0原文

我的 Qt 应用程序使用 Q_ASSERT_X,它调用 qFatal(),它(默认情况下)会中止应用程序。这对于应用程序来说非常有用,但我想在对应用程序进行单元测试时抑制这种行为。 (我正在使用 Google 测试框架。)我在单独的单元测试中进行了单元测试项目,静态链接到我正在测试的类。 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();
}

但我的应用程序仍然停在断言处。我可以看出我的自定义处理程序正在被调用,因为运行测试时的输出是:

我的致命错误:ASSERT 失败 MyClass::doSomething: "doSomething()", 文件 myclass.cpp,第 21 行 程序 意外地完成了。

即使断言失败,我该怎么做才能让我的测试继续运行?

My Qt application uses Q_ASSERT_X, which calls qFatal(), which (by default) aborts the application. That's great for the application, but I'd like to suppress that behavior when unit testing the application. (I'm using the Google Test Framework.) I have by unit tests in a separate project, statically linking to the class I'm testing. The documentation for qFatal() reads:

Calls the message handler with the
fatal message msg. If no message
handler has been installed, the
message is printed to stderr. Under
Windows, the message is sent to the
debugger.

If you are using the default message
handler this function will abort on
Unix systems to create a core dump. On
Windows, for debug builds, this
function will report a _CRT_ERROR
enabling you to connect a debugger to
the application.

...

To supress the output at runtime,
install your own message handler with
qInstallMsgHandler().

So here's my main.cpp file:

#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();
}

But my application is still stopping at the assert. I can tell that my custom handler is being called, because the output when running my tests is:

My Fatal: ASSERT failure in
MyClass::doSomething: "doSomething()",
file myclass.cpp, line 21 The program
has unexpectedly finished.

What can I do so that my tests keep running even when an assert fails?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

止于盛夏 2024-09-06 13:31:48

Q_ASSERT_X 在进行发布构建时编译为空。

因此,对于单元测试,进行发布构建,它不会调用 qFatal。

Q_ASSERT_X compiles to nothing when doing a release build.

So, for unit testing, do a release build and it will not call qFatal.

喜爱纠缠 2024-09-06 13:31:48

-DqFatal=qCritical :)

-DqFatal=qCritical :)

旧城烟雨 2024-09-06 13:31:48

至少对于 Qt-4.6.2,你无能为力。

src/corelib/global/qglobal.cpp 定义了 void qt_message_output(QtMsgType msgType, const char *buf) ,它首先检查是否已安装处理程序。如果是,则调用它,否则使用默认处理程序。紧接着,它几乎总是中止(Unix/MingWn)或调用退出(其他)。

我无法在线找到当前源代码的浏览器,但是 Qt-4.2.2 源代码基本相同,应该让您大致了解发生了什么。

At least for Qt-4.6.2, there's nothing you can do.

src/corelib/global/qglobal.cpp defines void qt_message_output(QtMsgType msgType, const char *buf) which first checks to see if a a handler has been installed. If so it calls it, otherwise it uses the default handlers. Immediately after that, it almost always aborts (Unix/MingWn) or calls exit (others).

I couldn't find a browser to the current source code online, but the Qt-4.2.2 source code is mostly identical and should give you a general idea what's happening.

一个人的旅程 2024-09-06 13:31:48

在某些情况下,您可能无法抑制 qFatal 并继续静默,被测试的组件可能处于这样的状态,无论如何在几行之后就会发生崩溃。避免这种情况的一种方法可能是在测试代码中的某个地方存根 qFatal ;)

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

然后你可以有一些自己的断言宏:

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

并在你的代码中使用它,例如:

CUSTOM_QEXPECT_FAIL( testedObj->panicAtTheDisco() );

并不是说这在任何方面都是好的方法,只是试图证明这一点可以为这个问题做点什么。

另外,我没有仔细阅读,您正在静态链接到测试类。在这种情况下,存根可能不起作用,除非您将其构建到测试可执行文件中。

In some cases you might cannot surpress qFatal and continue silently, tested component might be in such state that crash will occur anyhow after few lines. One way to avoid that could be to stub qFatal somewhere at your test code ;)

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

Then you could have some own assert macro:

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

And use it in your code like:

CUSTOM_QEXPECT_FAIL( testedObj->panicAtTheDisco() );

Not saying that this is in any way nice approach, just trying to prove that something can be done for the issue.

Addition, I didn't read carefully enough that you are statically linking against tested class. Stubbing does not probably work in that case, only if you would build it into your test executable.

亢潮 2024-09-06 13:31:48

定义您自己的断言宏。这就是我们所做的。不难(复制 QT_ASSERT_X),然后您可以在运行时重试/忽略/调试,并且在单元测试中简单地失败。

Define your own assert macro. That's what we do. Not hard (copy QT_ASSERT_X) and then you can have retry/ignore/debug when running and simply fail in unit tests.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文