如何为Qt项目编写独立单元测试并配置CMake构建
Qt分离式测试项目解决方案
问题背景
已阅读Qt测试官方教程,但需求是构建主程序与测试程序分离的项目:主程序窗口含按钮,点击后QLabel显示数字;测试程序需模拟鼠标点击并验证QLabel值。存在以下问题:
- 如何让测试程序链接主程序以访问其成员?
- 如何编写测试项目的CMakeLists?
- 无法通过包含
ui_mainwindow.h创建实例访问MainWindow成员的困惑。
项目结构(建议调整build目录名为src,避免与编译输出目录混淆):
---root |---test |----CMakeLists.txt |----test.cpp |----test.h |---src |----main.cpp |----QMainWindow.cpp |----QMainWindow.h |----QMainWindow.ui |---CMakeLists.txt # 根目录CMake
原根目录CMakeLists内容:
cmake_minimum_required(VERSION 3.5) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) project(myproject VERSION 0.1 LANGUAGES CXX) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) set(PROJECT_SOURCES main.cpp QMainWindow.cpp QMainWindow.h QMainWindow.ui ) add_executable(myproject ${PROJECT_SOURCES}) target_link_libraries(myprojectPRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
解决方案
1. 让测试程序访问主程序成员的核心方法
直接编译主程序为可执行文件无法被测试程序链接访问内部成员,需将主程序的UI逻辑(MainWindow相关代码)封装成静态库,主程序的main.cpp仅作为入口链接该库,测试程序同样链接此库即可访问公开的类和成员。
至于无法通过ui_mainwindow.h访问成员的问题:UI生成的类是MainWindow的私有成员(通常命名为ui),外部无法直接访问。正确做法是在QMainWindow.h中提供公共接口暴露需要测试的功能,比如获取QLabel文本的方法:
// QMainWindow.h class QMainWindow : public QMainWindow { Q_OBJECT public: explicit QMainWindow(QWidget *parent = nullptr); ~QMainWindow(); // 新增公共接口,用于测试获取QLabel文本 QString getLabelText() const { return ui->label->text(); } private slots: void on_pushButton_clicked(); private: Ui::QMainWindow *ui; int counter = 0; };
2. 修改根目录CMakeLists.txt
将MainWindow相关代码打包成静态库,主程序入口单独编译并链接该库:
cmake_minimum_required(VERSION 3.5) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) project(myproject VERSION 0.1 LANGUAGES CXX) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) # 1. 构建主程序核心库(包含MainWindow逻辑) set(APP_LIB_SOURCES src/QMainWindow.cpp src/QMainWindow.h src/QMainWindow.ui ) add_library(app_core STATIC ${APP_LIB_SOURCES}) target_link_libraries(app_core PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) # 让库的头文件能被主程序和测试程序找到 target_include_directories(app_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) # 2. 构建主程序可执行文件 add_executable(myproject src/main.cpp) target_link_libraries(myproject PRIVATE app_core Qt${QT_VERSION_MAJOR}::Widgets) # 3. 添加测试子目录 add_subdirectory(test)
3. 编写测试目录的CMakeLists.txt
需要链接Qt的Test模块、主程序核心库app_core:
cmake_minimum_required(VERSION 3.5) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Test) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Test) set(TEST_SOURCES test.cpp test.h ) add_executable(myproject_test ${TEST_SOURCES}) target_link_libraries(myproject_test PRIVATE app_core Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Test ) # 注册测试(可选,支持ctest命令运行) add_test(NAME myproject_test COMMAND myproject_test)
4. 测试代码示例(test.cpp)
使用QTest模拟按钮点击并验证QLabel内容:
#include "test.h" #include "QMainWindow.h" #include <QTest> void TestMainWindow::testButtonClick() { QMainWindow window; // 初始状态验证 QCOMPARE(window.getLabelText(), QString("0")); // 模拟按钮点击 QTest::mouseClick(window.findChild<QPushButton*>("pushButton"), Qt::LeftButton); QCOMPARE(window.getLabelText(), QString("1")); // 多次点击验证 QTest::mouseClick(window.findChild<QPushButton*>("pushButton"), Qt::LeftButton); QCOMPARE(window.getLabelText(), QString("2")); } QTEST_MAIN(TestMainWindow) #include "test.moc"
test.h内容:
#ifndef TEST_H #define TEST_H #include <QObject> class TestMainWindow : public QObject { Q_OBJECT private slots: void testButtonClick(); }; #endif // TEST_H
内容的提问来源于stack exchange,提问作者Amnesie
相关产品推荐
相关产品推荐

