-
该测试类可以为多个测试用例共用,即可以有多个case入口与之绑定;(
下同,测试类基本都是这样,方便复用
)
-
使用相关宏进行声明定义;
-
line130为该case入口;
-
line125定义类型参数Types,当运行时会遍历该参数列表,执行case的入口;
-
其中line127、128声明并绑定了测试用例和参数对象;
-
line135注册了该测试用例;
-
注意,绑定了定义的测试类后,case入口就可以访问类的成员,比如这里是成员函数ConverterTest(),进而遍历执行case,所以运行测试用例时控制套会显示执行了5个用例;
3.继承testing::TestWithParam<T>
3.1.适用场景
-
看类型就知道和参数有关,是的,参数化测试;
-
什么?一个不够?还需要测试XX场景下的?还需要测试大数据量调用情况?还需要...,批量产生测试数据,并应用测试;
-
当然也可以灵活的使用,即可以应用其一部分长处,我曾经写过一个测试场景是不用其参数化的长处,而在其构建函数和SetUp函数中构造好一份测试对象,再用多个不同case的入口,测试该对象的不同功能接口,比如分别测增删改查相关的接口;当然这里也可以利用其参数化几何的特点,批量构造对象,批量测试...看自己测试的场景和目的了;
3.2.示例
这里展示测试Escape字符串的接口,StrCotent0为原始字符串,StrCotent0为Escape之后的字符串,当然因为特殊情况,有些字符串不需要Escape,用NeedEscape来标记;
struct EscapeData
EscapeData(string strContent0, string strContent1, bool needEscape)
StrContent0 = strContent0;
StrContent1 = strContent1;
NeedEscape = needEscape;
string StrContent0;
string StrContent1;
bool NeedEscape;
class TestEscapeString : public testing::TestWithParam<EscapeData>
protected:
void SetUp() override;
protected:
bool mNeedEscape;
string mStrContent0;
string mStrContent1;
- SetUp函数类似于初始化函数,每次用例执行(在此为遍历每一个参数执行时)首先都要执行SetUp函数 ;
- testing::TestWithParam<T>测试参数为T,可以访问T类型的成员;
- 即对测试参数的数据做进一步的处理,方便测试或有意为之;
void TestEscapeString::SetUp()
mStrContent0 = GetParam().StrContent0;
mStrContent1 = GetParam().StrContent1;
mNeedEscape = GetParam().NeedEscape;
- GenerateEscapeData函数为批量的创建测试参数;
- 上文说过SetUp函数对测试参数做了进一步解析和处理,并将结果保存在成员字段里;
- TEST_P为入口函数,此处可以访问测试类的成员,即可以访问测试数据(为方便测试而处理后的);
- 进而测试相关接口;
INSTANTIATE_TEST_CASE_P(ESCAPE, TestEscapeString, testing::ValuesIn(GenerateEscapeData()));
TEST_P(TestEscapeString, caseEscapeUnEscape)
string strConvert;
string strConvert2;
bool bNeed = JSONInterface::NeedUnEscape(mStrContent0, strConvert);
ASSERT_EQ(bNeed, mNeedEscape);
if (!bNeed)
return;
ASSERT_EQ(strConvert, mStrContent1);
// 此处省略
TEST(testRetoreEscapeSpecificPropertyChar1, testRetoreEscapeSpecificPropertyChar)
// 此处省略
4.Mock模拟行为
4.1适用场景
当数据格式已设计好,数据生成方和数据使用方可以同时开发,这时候数据使用方需要按照约定格式模拟相关接口;
当需要调用后端服务接口,而此接口还在开发中未开放,需要模拟接口;
其他场景。
4.2.示例
4.2.1.待测试接口
class ParseFileUtils : public ParseFileBase
public:
ParseFileUtils();
virtual ~ParseFileUtils();
shared_ptr<char> ParseBinaryFile(wstring filePath) override;
vector<vector<string>> ParseTextFileToGetComponents(wstring textFilePath, string flag) override;
vector<vector<string>> ParseTextFileToGetComponents(wstring textFilePath, string beginFlag, string endFlag) override;
4.2.2.测试代码编写
- 需要编写测试类,继承被测试类;
- 并声明要Mock哪些接口;
- 在测试时使用测试类代替被测试类,并预先定义调用接口时有什么行为(支持多种类型的行为,在不同测试用例下模拟不同行为);
class MockParseFileUtils : public ParseFileUtils
public:
MockParseFileUtils()
Init();
MOCK_METHOD1(ParseBinaryFile, shared_ptr<char>(wstring filePath));
MOCK_METHOD2(ParseTextFileToGetComponents, vector<vector<string>>(wstring textFilePath, string flag));
MOCK_METHOD3(ParseTextFileToGetComponents, vector<vector<string>>(wstring textFilePath, string flag, string endFlag));
shared_ptr<char> GetBinaryStream();
protected:
void Init();
// 此处省略
protected:
// 此处省略
- 该测试类可以为多个测试用例共用,即可以有多个case入口与之绑定;
- 针对文件无效场景的测试用例;
- 预先定义什么条件下条用接口会有什么行为,这里是模拟无效文件,所以返回nullptr和空数组;
using ::testing::Return;
using ::testing::_;
TEST(MockParseModelFile, MockBadModelFile)
// Mock解析文件接口,返回模拟数据
MockParseFileUtils obj;
EXPECT_CALL(obj, ParseBinaryFile(testing::_)).Times(1).WillOnce(Return(shared_ptr<char>(nullptr)));
EXPECT_CALL(obj, ParseTextFileToGetComponents(testing::_, testing::_)).Times(1).WillOnce(Return(vector<vector<string>>()));
EXPECT_CALL(obj, ParseTextFileToGetComponents(testing::_, testing::_, testing::_)).Times(1).WillOnce(Return(vector<vector<string>>()));
ViewDataInfo dataInfo(L"UTV", L"NAME", L"Case1", L"VIEWLOCMOCK", L"PROPLOCMOCK", L"THUMBLOCMOCK");
Exporter exporter(dataInfo, L"D:\\TestFile\\Mock", &obj);
Result* result = exporter.Run();
- 该测试类可以为多个测试用例共用,即可以有多个case入口与之绑定;
- 针对文件正常场景的测试用例;
- 预先定义什么条件下条用接口会有什么行为,这里是模拟正常文件,所以调用其他函数返回模拟的正常数据;
TEST(MockParseModelFile, MockNormalModelFile)
// Mock解析文件接口,返回模拟数据
MockParseFileUtils obj;
EXPECT_CALL(obj, ParseBinaryFile(testing::_)).Times(1).WillOnce(Return(obj.GetFileBinaryStream()));
EXPECT_CALL(obj, ParseTextFileToGetComponents(testing::_, testing::_)).Times(1).WillOnce(Return(vector<vector<string>>()));
EXPECT_CALL(obj, ParseTextFileToGetComponents(testing::_, testing::_, testing::_)).Times(1).WillOnce(Return(vector<vector<string>>()));
// 此处省略
- 当然可以定义多种条件下接口的行为,有兴趣的可以多多尝试;
- 别忘了测试项目(可执行程序exe)的入口为:
int _tmain(int argc, _TCHAR* argv[])
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
int nRe = RUN_ALL_TESTS();
system("pause");
return nRe;
5.原理及流程
- 根据自己的使用和理解,绘制了一张GTest/GMock测试原理流程图,供参考,
上一篇博客讲述了开发阶段编写单元测试的意义,对此不再做赘述,实战用法如下。1.TEST1.1.适用场景用法简单,几乎适用于任何单一接口的测试; 真是一直用一直爽;1.2.示例TEST(Normal, NormalTest){ ASSERT_EQ(Setting::IsSqlConnected());}2.继承testing::Test2.1.适用场景当测试一系列与类型相关的重载接口或功能相近的接口时; 其他与类型相关的场景; 灵活运用,利用其部分特点创造.
catch_
gmock_integration
当
使用 catch.hpp 测试框架时,允许 EXPECT_CALL 和其他
gmock 函数工作的代码倾倒场。
随意从这个 repo 中窃取。 我不关心许可证,会接受拉取请求。
这是概念证明,而不是库。
git clone mkdir build && cd build cmake .. && make && make test
肉在哪里?
./test/suite1/
gmock_catch_interceptor.cpp ./test/suite1/main.cpp
注意主要仍然初始化谷歌测试。
GMock 依赖
GTest 进行编译,不知道为什么。 我删除了打印到屏幕/输出文件的默认侦听器。
安装了一个侦听器以具有
GMock 的挂钩点。
GMock 在模拟对象的拆卸时执行,然后作为生命周期的一部分通知侦听器。
项目级C语言单元测试框架, 一键生成, 无代码侵入
支持gtest gmock语法, 支持桩函数开关,真实/模拟随时切换
自动打桩 ,自动编译 ,提高 编码效率 代码质量, 快速入门
代码覆盖率自动显示,详细的项目级测试报告
windows linux 嵌入式环境,多平台支持,支持命令行与GUI界面。
gtest是谷歌为C++开发的单元测试框架,该框架基于xUnit架构。gtest提供了较丰富的测试特性,且其命令行方式输出界面友好美观,是C++单元测试工具的较佳选择。
1 gtest环境部署
先从这里下载到gtest源码包,解压后执行如下命令:
./configure
这里google没有提供make install行为来安装,我们需要手动安装。继续执行以下命令:
cp li
有时为了完整的测试一个函数的正确性,我们需要测试给定各种不同输入的情况下,函数的输出是否正确。最直接的方法就是我们手动去给不同输入,然后测试输出是否正确。但是这种方式工作量大,并且都是重复性,无意义的操作。为此,
gtest中提供了参数化的测试。
2、参数化测试
使用方法
要
使用参数化测试,我们需要创建一个子类继承testing::TestWithParam
文章目录前言1. 下载网址2. 为什么选择Google Mock3.
C++简单的例子3.1
使用流程4. 指定自己的期望
在
进行单元测试时,我们想要测试自己缩写函数A,但是函数A却依赖于函数B,当函数B无法满足预期时就无法对函数A
进行测试,主要由于下面几个原因:
函数B依赖于硬件设备
真实的函数B的返回值无法满足我们的预期
团队开发中函数B尚未实现
这时就需要对函数B
进行打桩(仿真mock),使其达到我们预期的效果。
但是如同下面这种类型函数时,则需要深入下去,对基层的函数
进行打桩:
目录一、简单Demo二、断言2.1 ASSERT和EXPECT2.2 流三、测试TEST()四、调用测试和main()
上文(C++开发测试工具gmock的安装与使用超详解)介绍了gmock的安装、配置与基本使用案例,本文将详细介绍一下gmock的基本语法,结合上文一起食用效果更佳哦~
一、简单Demo
首先来编写一个简单Demo,编写代码之前,首先需要将解决方案的平台与目标程序一致,这里选择的是x64,然后版本也要与目标程序一致,这里选择的是release版本。
新建一个头文件,命名为demo.h,声明