Visual Studio测试工具集成GoogleTest和Qt
Visual Studio 的测试管理工具虽然集成了 Google Test 测试框架,但缺少 QtTest 测试框架的支持,所以需要在 Google Test 集成 Qt 框架完成单元测试。
背景介绍
因为代码中不免需要编写单元测试,而且可能一个 VC 项目中带有若干个测试用例,这时难免有运行调试其中一个测试用例。
虽然 Visual Studio 本身有测试管理工具(Test Explorer),但目前官方维护和支持的测试框架[1]只有 Google Test 、Boost Test 和 MS CppUnit Test Framework。
所以,采用简单的解决方案是在 Google Test 测试框架基础上,使其支持 Qt 框架。
问题描述
- 如何让 Google Test 运行在 Qt 的事件循环中?
- 如何使 Visual Studio 的测试管理工具(环境变量)能正常运行?
测试环境
- Visual Studio 2019 Community
- Test Adapter for Google Test[2]
- Qt VS Tools[3]
- Qt 5.15.2 ( msvc2019_64 )
创建项目
创建“Qt Core Application”项目,在 Qt Modules 中选择 Core 和 Test。
完成项目创建后,右键 Manage NuGet Packages...,搜索并引入 GoogleTest 测试框架,NuGet 包名 是 Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn
。
右键项目“Properties > Referenced Packages > Google Test”,设置 Use Google Test's main Function
为 No
。因为我们需要手动编写 main
函数,以便 Google Test 能够正常启动 Qt 事件循环。
创建简单的测试启动类
修改 main.cpp
,使 Google Test 运行在事件循环中。
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
::testing::InitGoogleTest(&argc, argv);
QTimer::singleShot(0, []() { QCoreApplication::exit(RUN_ALL_TESTS()); });
return a.exec();
}
编写测试单元
结合 QtTest [4]简单写了 QString::toUpper
方法的单元测试。
namespace QStringTests
{
TEST(toUpper, AllLower)
{
QString string = "hello";
EXPECT_EQ("HELLO", string.toUpper());
}
TEST(toUpper, Mixed)
{
QString string = "Hello";
EXPECT_EQ("HELLO", string.toUpper());
}
TEST(toUpper, AllUpper)
{
QString string = "HELLO";
EXPECT_EQ("HELLo", string.toUpper()); // failed
}
}
编译运行后,可以看到类似的运行结果。
[==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 3 tests from toUpper
[ RUN ] toUpper.AllLower
[ OK ] toUpper.AllLower (0 ms)
[ RUN ] toUpper.Mixed
[ OK ] toUpper.Mixed (0 ms)
[ RUN ] toUpper.AllUpper
D:\repos\TestQString\TestQString.cpp(21): error: Expected equality of these values:
"HELLo"
Which is: 00007FF6978C7A58
string.toUpper()
Which is: { 2-byte object <48-00>, 2-byte object <45-00>, 2-byte object <4C-00>, 2-byte object <4C-00>, 2-byte object <4F-00> }
[ FAILED ] toUpper.AllUpper (2 ms)
[----------] 3 tests from toUpper (5 ms total)
[----------] Global test environment tear-down
[==========] 3 tests from 1 test case ran. (8 ms total)
[ PASSED ] 2 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] toUpper.AllUpper
1 FAILED TEST
D:\repos\TestQString\x64\Debug\TestQString.exe (process 6740) exited with code 1.
扫描测试用例
打开菜单“View > Test Explorer”,会多出测定管理工具,但是执行扫描不出意外会出现错误,因为扫描程序运行其实没有设置 Qt 的环境变量。
设置单元测试运行环境
Visual Sutdio 测试工具按照项目配置运行环境[5]。
在当前项目目录下创建文件 Qt.x64.runsettings
。
<!--?xml version="1.0" encoding="utf-8"?-->
<runsettings>
<runconfiguration>
<environmentvariables>
<path>%PATH%;C:/Qt/5.15.2/msvc2019_64/bin</path>
</environmentvariables>
</runconfiguration>
</runsettings>
卸载项目(Unload),并编辑项目,添加属性(PropertyGroup)。
<propertygroup>
<runsettingsfilepath>$(MSBuildProjectDirectory)\Qt.$(Platform).runsettings</runsettingsfilepath>
</propertygroup>
重新打开项目,并且 Rebuild 后,可以在 Test Explorer 窗口中看到刚才声明的单元测试列表,并且可以针对若干个特定单元进行运行测试。
配置T4模板文件
通过创建 T4 模板文件[6] 来解决 *.runsettings
的 Qt 固定路径写法存在问题,以此方便不同 Qt 环境切换。
重命名 Qt.x64.runsettings
为 Qt.runsettings.tt
,并修改文件内容。
<#@ template language="c#" hostspecific="true" #>
<#@ output extension=".runsettings" #>
<#@ parameter type="System.String" name="QtDllPath" #>
<!--?xml version="1.0" encoding="utf-8"?-->
<runsettings>
<runconfiguration>
<environmentvariables>
<path>%PATH%;<#= QtDllPath #></path>
</environmentvariables>
</runconfiguration>
</runsettings>
卸载项目配置 T4 模板构建任务,编辑项目文件内容。
- <none include="Qt.runsettings.tt">
+ <itemgroup>
+ <none include="Qt.runsettings.tt">
+ <generator>TextTemplatingFileGenerator</generator>
+ <outputfilename>$(MSBuildProjectDirectory)\Qt.$(Platform).runsettings</outputfilename>
+ </none>
+ <t4parametervalues include="QtDllPath">
+ <value>$(QtDllPath)</value>
+ </t4parametervalues>
+ </itemgroup>
<propertygroup>
<runsettingsfilepath>$(MSBuildProjectDirectory)\Qt.$(Platform).runsettings</runsettingsfilepath>
+ <transformonbuild>true</transformonbuild>
</propertygroup>
+ <import project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TextTemplating\Microsoft.TextTemplating.targets">
打开项目,执行 Rebuild,如果看到如下编译输出,并且当前项目出现 Qt.x64.runsettings
,代表生成成功。
....
1>Transforming template Qt.runsettings.tt...
....
运行截图
https://docs.microsoft.com/zh-cn/visualstudio/test/writing-unit-tests-for-c-cpp?view=vs-2019 ↩︎
https://docs.microsoft.com/zh-cn/visualstudio/test/how-to-use-google-test-for-cpp?view=vs-2019 ↩︎
https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019 ↩︎
https://doc.qt.io/qt-5.15/qttestlib-tutorial2-example.html ↩︎
https://docs.microsoft.com/zh-cn/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file?view=vs-2019 ↩︎
https://docs.microsoft.com/en-us/visualstudio/modeling/writing-a-t4-text-template?view=vs-2019 ↩︎
原文地址:https://www.cnblogs.com/uwyc/p/14878748.html
- 利用Volatility查找系统中的恶意DLL
- 雪人行动:利用IE10 0day漏洞的APT攻击剑指美国军方情报
- Android开发:最详细的 Toolbar 开发实践总结
- 关于yubikey对web应用的杞人之忧
- 利用旧版Android漏洞的E-Z-2-Use攻击代码已在Metasploit发布
- Android Studio你不知道的调试技巧
- Android 数据绑定框架DataBinding,堪称解决界面逻辑的黑科技
- 汽车黑客:没有Security就没有Safety
- Android 自定义View高级特效,神奇的贝塞尔曲线
- Android二维码扫描开发(一):实现思路与原理
- 说一道简单的BCTF题 – 分分钟而已
- 安全扫描工具Nmap引擎理解文档
- AppFuse项目笔记(1)
- 电子商务系统ShopNC多个漏洞(可暴力 getshell)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- sam2tsv用法
- GridSearchCV (scikit learn) 确定超参数
- 10k+点赞的SpringBoot后台管理系统竟然出了详细教程!爱了!
- 数据库备份和恢复
- 在jupyter里面运行conda虚拟环境的R
- 重新夺回对 /etc/resolv.conf 的控制权
- plsql
- 打卡群2刷题总结1008——环形链表
- Oracle数据库的对象
- 打卡群刷题总结1008——加油站
- 打卡群刷题总结1005——跳跃游戏
- 真是活久见,在 Minecraft 的虚拟游戏里竟然还能管理 Kubernetes!
- 打卡群2刷题总结1007——反转链表
- 打卡群2刷题总结1001——两数之和 II - 输入有序数组
- 复杂一点的SQL语句