如何为Qt Creator生成的QML模块可执行程序添加QML单元测试
解决Qt Quick应用QML单元测试中模块导入失败问题
问题场景
基于Qt 6.6 + CMake构建的Quick应用,添加QML单元测试时出现QuickApp模块导入失败,报错信息如下:
QWARN : QuickAppTest::tst_main::compile() /Users/qwqqqw/dev/QuickApp/tst_main.qml produced 2 error(s): /Users/qwqqqw/dev/QuickApp/tst_main.qml:5,1: Type Main unavailable qrc:/qt/qml/QuickApp/Main.qml: No such file or directory Working directory: /Users/qwqqqw/dev/build-QuickApp-Qt_6_6_1_for_macOS-Debug Import paths: '/Users/qwqqqw/dev/build-QuickApp-Qt_6_6_1_for_macOS-Debug' 'qrc:/qt-project.org/imports' 'qrc:/qt/qml' '/Users/qwqqqw/dev/Qt/6.6.1/macos/qml' Plugin paths: '.' FAIL! : QuickAppTest::tst_main::compile() Type Main unavailable
手动删除构建目录自动生成的qmldir文件中的prefer :/qt/qml/QuickApp/语句后,测试可正常运行。
原项目CMakeLists核心代码:
qt_add_executable(appQuickApp main.cpp ) qt_add_qml_module(appQuickApp URI QuickApp VERSION 1.0 QML_FILES Main.qml )
测试相关代码:
add_executable(appQuickAppTest tst_main.cpp tst_main.qml ) target_compile_definitions(appQuickAppTest PRIVATE -DQUICK_TEST_SOURCE_DIR="${CMAKE_SOURCE_DIR}" ) target_link_libraries(appQuickAppTest PRIVATE Qt6::QuickTest Qt6::Quick )
原因分析
原项目中qt_add_qml_module将QML模块直接绑定到主可执行文件appQuickApp,QML文件被嵌入到主程序的资源包中。自动生成的qmldir会添加prefer :/qt/qml/QuickApp/语句,让QML引擎优先从资源路径加载模块,但测试程序appQuickAppTest无法访问主程序的资源,因此找不到Main.qml。
解决方法
方案1:将QML模块改为独立库模块
把QML模块从主可执行文件分离为单独的库目标,使主程序和测试程序都能链接该库共享模块:
# 替换原绑定到appQuickApp的qml模块,创建独立QML库 qt_add_qml_module(QuickApp URI QuickApp VERSION 1.0 QML_FILES Main.qml TYPE STATIC # 也可选择SHARED,按需调整 ) # 主程序链接独立QML库 target_link_libraries(appQuickApp PRIVATE Qt6::Quick QuickApp ) # 测试程序同样链接该库 target_link_libraries(appQuickAppTest PRIVATE Qt6::QuickTest Qt6::Quick QuickApp )
此方案下生成的qmldir不会指向资源路径,测试程序可正常加载模块。
方案2:禁用QML模块的资源优先加载
在原qt_add_qml_module中添加NO_RESOURCE_PREFIX选项,避免生成资源优先的qmldir:
qt_add_qml_module(appQuickApp URI QuickApp VERSION 1.0 QML_FILES Main.qml NO_RESOURCE_PREFIX )
或者通过设置目标属性实现:
set_target_properties(appQuickApp PROPERTIES QT_QML_MODULE_PREFER_DISK_PATH ON )
两种方式都会让qmldir不再包含prefer语句,测试程序可直接从磁盘路径加载QML文件。
方案3:为测试程序添加QML导入路径
无需修改原项目结构,通过设置测试程序的QML导入路径指向原项目QML模块的磁盘位置:
# 在CMake中添加编译定义指定导入路径 target_compile_definitions(appQuickAppTest PRIVATE -DQUICK_TEST_SOURCE_DIR="${CMAKE_SOURCE_DIR}" -DQML_IMPORT_PATH="${CMAKE_BINARY_DIR}/qml/QuickApp" ) # 或者添加运行时环境变量设置导入路径 add_custom_command(TARGET appQuickAppTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E env "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/qml/QuickApp" $<TARGET_FILE:appQuickAppTest> )
也可在测试的C++代码中手动设置导入路径:
#include <QtQuickTest/quicktest.h> #include <QQmlEngine> int main(int argc, char *argv[]) { QQmlEngine::setImportPathList({ QStringLiteral("%1/qml/QuickApp").arg(CMAKE_BINARY_DIR), QQmlEngine::importPathList() }); return quick_test_main(argc, argv, "QuickAppTest", QStringLiteral(QUICK_TEST_SOURCE_DIR)); }
内容的提问来源于stack exchange,提问作者psyched
相关产品推荐
相关产品推荐

