You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Qt项目编写独立单元测试并配置CMake构建

Qt分离式测试项目解决方案

问题背景

已阅读Qt测试官方教程,但需求是构建主程序与测试程序分离的项目:主程序窗口含按钮,点击后QLabel显示数字;测试程序需模拟鼠标点击并验证QLabel值。存在以下问题:

  1. 如何让测试程序链接主程序以访问其成员?
  2. 如何编写测试项目的CMakeLists?
  3. 无法通过包含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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:16:08