第 2 章:数据驱动测试
本章演示了如何使用不同的测试数据多次执行测试。
到目前为止,我们一直将需要测试的数据硬编码到测试函数中。如果添加更多测试数据,该函数可能会变成这样:
QCOMPARE(QString("hello").toUpper(), QString("HELLO"));
QCOMPARE(QString("Hello").toUpper(), QString("HELLO"));
QCOMPARE(QString("HellO").toUpper(), QString("HELLO"));
QCOMPARE(QString("HELLO").toUpper(), QString("HELLO"));为避免函数因重复代码而显得杂乱,Qt Test 支持将测试数据添加到测试函数中。我们只需在测试类中添加另一个私有槽即可:
class TestQString: public QObject
{
Q_OBJECT
private slots:
void toUpper_data();
void toUpper();
};编写数据函数
测试函数关联的数据函数名称后会附加 `_data `。我们的数据函数如下所示:
void TestQString::toUpper_data()
{
QTest::addColumn<QString>("string");
QTest::addColumn<QString>("result");
QTest::newRow("all-lower") << "hello" << "HELLO";
QTest::newRow("mixed") << "Hello" << "HELLO";
QTest::newRow("all-upper") << "HELLO" << "HELLO";
}首先,我们使用 `QTest::addColumn()` 函数定义测试表中的两个元素:一个测试字符串,以及对该字符串应用 `QString::toUpper()` 函数后得到的预期结果。
然后,我们使用QTest::newRow()函数向表中添加一些数据。如果需要对行名中的某些数据进行格式化——例如在迭代生成大量数据行时——我们也可以使用QTest::addRow()函数。每行数据都将成为测试表中的一行。
QTest::newRow() 函数接受一个参数:一个将与数据集关联并在测试日志中用于标识数据行的名称。QTest::addRow() 函数接受一个(printf 风格的)格式字符串,后面跟上要替换格式字符串中格式化标记的参数。然后,我们将数据集流式写入新的表行中。 首先是一个任意字符串,然后是将QString::toUpper()函数应用于该字符串后得到的预期结果。
您可以将测试数据视为一个二维表。在本例中,它包含两列,分别名为string 和result ,以及三行。此外,每行都关联有一个名称和一个索引:
| 索引 | 名称 | 字符串 | 结果 |
|---|---|---|---|
| 0 | 全部小写 | "hello" | HELLO |
| 1 | 混合 | "Hello" | 你好 |
| 2 | 全大写 | “HELLO” | HELLO |
当数据流式传输到该行时,每个数据项都会经过断言,以确保其与所填充列的类型相匹配。如果任何断言失败,测试将中止。
在给定测试函数的数据表中,行名和列名应保持唯一:如果两行或两列名称相同,则会(自 Qt 6.5 起)触发警告。 请参阅qWarning() 以了解如何将警告视为错误,并参阅《测试中的警告》以了解如何让测试摆脱其他警告。
重写测试函数
现在我们可以重写该测试函数:
void TestQString::toUpper()
{
QFETCH(QString, string);
QFETCH(QString, result);
QCOMPARE(string.toUpper(), result);
}TestQString::toUpper() 函数将被执行三次,分别对应我们在关联的 TestQString::toUpper_data() 函数中创建的测试表中的每一条条目。
首先,我们使用QFETCH()宏获取数据集中的两个元素。QFETCH()接受两个参数:元素的数据类型和元素名称。然后,我们使用QCOMPARE()宏执行测试。
这种方法使得在不修改测试本身的情况下,非常容易向测试中添加新数据。
准备独立可执行文件
同样,要使我们的测试用例成为一个独立可执行文件,需要添加以下两行代码:
QTEST_MAIN(TestQString)
#include "testqstring.moc"与之前一样,QTEST_MAIN() 宏会展开为一个简单的 main() 方法,该方法会运行所有测试函数;由于测试类的声明和实现都位于 .cpp 文件中,我们还需要包含生成的 moc 文件,以确保 Qt 的反射功能正常工作。
构建可执行文件
您可以使用 CMake 或 qmake 构建测试用例可执行文件。
使用 CMake 构建
在 CMakeLists.txt 文件中配置构建设置:
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(tutorial2 LANGUAGES CXX)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Test Widgets)
qt_standard_project_setup()
qt_add_executable(tutorial2
testqstring.cpp
)
set_target_properties(tutorial2 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(tutorial2 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Test
Qt6::Widgets
)
install(TARGETS tutorial2
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
qt_generate_deploy_app_script(
TARGET tutorial2
OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})接下来,在命令行中运行 `cmake `,或使用位于 `Qt-prefix/<version>/<platform>/bin/qt-cmake` 目录下的便捷脚本 `qt-cmake `:
<Qt-prefix>/<version>/<platform>/bin/qt-cmake <source-dir> <build-dir> -G Ninja然后,运行您首选的生成器工具来构建可执行文件。这里我们使用的是 Ninja:
ninja使用 qmake 进行构建
在.pro 文件中配置您的构建设置:
QT += widgets testlib
SOURCES = testqstring.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/qtestlib/tutorial2
INSTALLS += target接下来,运行qmake ,最后运行make 来构建可执行文件:
qmake
make运行可执行文件
运行生成的可执行文件应显示以下输出:
********* Start testing of TestQString *********
Config: Using QtTest library %VERSION%, Qt %VERSION%
PASS : TestQString::initTestCase()
PASS : TestQString::toUpper(all-lower)
PASS : TestQString::toUpper(mixed)
PASS : TestQString::toUpper(all-upper)
PASS : TestQString::cleanupTestCase()
Totals: 5 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms
********* Finished testing of TestQString *********© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.