GTEST 一文全懂
TEST 接口介绍
根据 GTEST DOCs 可知,gtest 提供了三个接口用于测试,分别如下:
- TEST(TestName, FuncX)
该API将会生成 TestName.FuncX 的测试用例,每个测试用例单独存在无关联,可用于绝大多数零散的测试 - TEST_F(ClassName, FuncY)
该API将会生成 ClassName.FuncY 的测试用例,实现基于::testing::TEST
,适用于多个测试场景需要相同数据配置的情况 - TEST_P
该API联合INSTANTIATE_TEST_CASE_P
宏使用,实现基于::testing::TestWithParam<T>
,用于多个场景流程相同,但是需要配置不同参数完成的情况。该API也是封装性最强的接口,略微复杂。
1. ::testing::TEST 介绍
该类主要有四个虚函数:
static void SetUpTestSuite/SetUpTestCase() {}
该函数主要用于整个应用于ClassName测试的配置工作static void TearDownTestSuite/TearDownTestCase() {}
该函数主要用于整个应用于ClassName测试的销毁工作virtual void SetUp();
该函数主要用于整个应用于ClassName中某个Case测试的配置工作virtual void TearDown();
该函数主要用于整个应用于ClassName中某个Case测试的销毁工作
执行流程总结如下:
SetUpTestSuite() ->
case1
ClassName::Construtor()构造函数 ->
SetUp() ->
CASE具体的执行过程 ->
TearDown() ->
ClassName::~Construtor()析构函数 ->
case2
ClassName::Construtor()构造函数 ->
SetUp() ->
CASE具体的执行过程 ->
TearDown() ->
ClassName::~Construtor()析构函数 ->
casen
…
TearDownTestSuite()
2. ::testing::TestWithParam< T > 介绍
T 可以实现模板,定义自己的参数接口,INSTANTIATE_TEST_CASE_P 宏定义如下:
#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...)
第三个参数就是需要指定的参数,这些参数由参数生成器 ParamGenerator完成,gtest提供了如下参数生成器:
参数生成器 | 说明 |
---|---|
Range(begin, end[, step]) | 范围在begin~end之间,步长为step,不包括end |
Values(v1, v2, …, vN) | v1,v2到vN的值 |
ValuesIn(container) and ValuesIn(begin, end) | 从一个C类型的数组或是STL容器,或是迭代器中取值 |
Bool() | 取false 和 true 两个值 |
Combine(g1, g2, …, gN) | 这个比较强悍,它将g1,g2,…gN进行排列组合,g1,g2,…gN本身是一个参数生成器,每次分别从g1,g2,…gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。说明:这个功能只在提供了<tr1/tuple>头的系统中有效。gtest会自动去判断是否支持tr/tuple,如果你的系统确实支持,而gtest判断错误的话,你可以重新定义宏GTEST_HAS_TR1_TUPLE=1 |
TEST 接口实践
因为TEST过于简单,在这里就不做多说明了,接下来简要说明下TEST_F
以及TEST_P
1. TEST_F
示例代码如下,可以根据之前对于4个虚函数的介绍 将适当的函数放在不同的虚函数中完成。
class TestCase:public ::testing::Test {
......
};
TEST_F(TestCase, proc_name) {
......
}
2. TEST_P
如果我想完成一个测试类,然后大部分代码都差不多,只是配置不同的变量完成诸多case的测试,那么TEST_P无疑是最好的选择。根据我的测试,参数生成器::testing::Values
则可以完成大部分工作,只要将我们需要的参数封装进一个class 就行了。
//Step1:申明一个呼叫参数类,该类主要用于TEST_P宏中实现的测试逻辑使用
class CallArgs
{
public:
CallArgs(bool hasAudio, const char *hasVideo, std::vector<ProcessControlTestInterface>& resetG):
_hasAudio(hasAudio),_hasVideo(hasVideo),_resetGroup(resetG){}
bool audio(){ return _hasAudio;}
std::string video(){ return _hasVideo;}
// std::vector<ProcessControlTestInterface> group(){ return _resetGroup;} // success
std::vector<ProcessControlTestInterface>& group(){ return _resetGroup;} // success
private:
bool _hasAudio;
std::string _hasVideo;
// std::vector<ProcessControlTestInterface> _resetGroup; // success.
std::vector<ProcessControlTestInterface>& _resetGroup; // success.
};
//Step2:申明一个呼叫类,该类同时也是TEST_P宏的第一个参数test_case_name
// 该类继承了TestWithParam<CallArgs>模版类,从而使得CallArgs类与Call类进行了关联。
class Call: public ::testing::TestWithParam<CallArgs>
{
};
//Step3: 使用INSTANTIATE_TEST_CASE_P宏,对Call类进行类相关多个的参数设置
// 这里只添加了两个参数CallArgs(true,true)和CallArgs(true,false),事实上,可以添加多大50个参数。
// 这里使用参数生成器::testing::Values,GTest定义了了很多参数生成器。
std::vector<ProcessControlTestInterface> resetGroup = {test_VolumeMute_1_Block5_gain_n, test_ToneControl_Block4};
INSTANTIATE_TEST_CASE_P(VOIP, Call, ::testing::Values(
CallArgs(true, "1", resetGroup),
CallArgs(true, "2", resetGroup)
) );
//Step4: 编写了使用TEST_P宏实现的测试用例
// 使用了TestWithParam<CallArgs>类的GetParam()接口获取参数CallArgs
// 实际上这是两个测试用例,即该代码段会执行两个,参数分别为CallArgs(true,true)和CallArgs(true,false)
TEST_P( Call, makeCall)
{
CallArgs args = GetParam();
TRACE_INFO1("CallArgs.video:%s", args.video().c_str());
ASSERT_TRUE(args.audio());
TRACE_INFO1("CallArgs.audio:%d", args.audio());
EXPECT_EQ("1", args.video());
std::vector<ProcessControlTestInterface> group = args.group();
TRACE_INFO1("==== CallArgs.group.size() %d ====", group.size());
std::vector<ProcessControlTestInterface>::iterator iter;
for(iter = group.begin(); iter != group.end(); ++iter) {
if(*iter != NULL) {
}
}
}
- 原文有错误,makeCall 只是一个符号,不代表实际意义。
- 这里的ProcessControlTestInterface 只是一个函数模型,自己定义的,只做测试,无其他含义。
参考链接:
参数生成器