一、TestCase的介绍
Gtest提供了若干个case方法进行测试不同的用例。主要常见的有TEST/TEST_F及TEST_P宏的使用。
在每个TestCase中可以通过断言(Assert)提供的方法,检查程序的走向是否符合期望的结果,从而以此来判定程序的正确性。
在同一份TestCase中不能同时出现TEST和TEST_F两者进行混用;
二、断言
Google Test采用一系列的断言(assertion)来进行代码测试,这些宏有点类似于函数调用。
当断言失败时Google Test将会打印出assertion时的源文件和出错行的位置,以及附加的失败信息,
用户可以直接通过“<<”在这些断言宏后面跟上自己希望在断言命中时的输出信息。
测试宏可以分为两大类:ASSERT_*和EXPECT_*,这些成对的断言功能相同,但效果不同。其中ASSERT_*将会在失败时产生致命错误并中止当前调用它的函数执行。EXPECT_*版本的会生成非致命错误,不会中止当前函数,而是继续执行当前函数。通常情况应该首选使用EXPECT_*,因为ASSERT_*在报告完错误后不会进行清理工作,有可能导致内容泄露问题。
基本断言
Fatal assertion Nonfatal assertion Verifies
ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false
二值比较
Fatal assertion Nonfatal assertion Verifies
ASSERT_EQ(val1,val2); EXPECT_EQ(val1,val2); val1 == val2
ASSERT_NE(val1,val2); EXPECT_NE(val1,val2); val1 != val2
ASSERT_LT(val1,val2); EXPECT_LT(val1,val2); val1 < val2
ASSERT_LE(val1,val2); EXPECT_LE(val1,val2); val1 <= val2
ASSERT_GT(val1,val2); EXPECT_GT(val1,val2); val1 > val2
ASSERT_GE(val1,val2); EXPECT_GE(val1,val2); val1 >= val2
字符串比较
Fatal assertion Nonfatal assertion Verifies
ASSERT_STREQ(str1,str2); EXPECT_STREQ(str1,str2); the two C strings have the same content
ASSERT_STRNE(str1,str2); EXPECT_STRNE(str1,str2); the two C strings have different content
ASSERT_STRCASEEQ(str1,str2); EXPECT_STRCASEEQ(str1,str2); the two C strings have the same content, ignoring case
ASSERT_STRCASENE(str1,str2); EXPECT_STRCASENE(str1,str2); the two C strings have different content, ignoring case
三、TEST宏
TEST宏的作用是创建一个简单的测试用例,它定义了一个测试函数,在这个函数里可以使用任何C++代码并使用提供的断言([断言类型介绍])来进行检查。
TEST语法定义:
TEST(test_case_name, test_name)
test_case_name第一个参数是测试用例名,通常是取测试函数名或者测试类名
test_name 第二个参数是测试名这个随便取,但最好取有意义的名称
当测试完成后显示的测试结果将以"测试用例名.测试名"的形式给出
#include <gtest/gtest.h>
inline int Add(int i, int j) { return i + j; }
TEST(Add, 负数) {
EXPECT_EQ(Add(-1, -2), -3);
EXPECT_GT(Add(-4, -5), -6); // 故意的
}
TEST(Add, 正数) {
EXPECT_EQ(Add(1, 2), 3);
EXPECT_GT(Add(4, 5), 6);
}
int main(int argc, char **argv) {
std::cout << "Running main() from gtest_main.cc\n";
testing::InitGoogleTest(&argc, argv);
RUN_ALL_TESTS();
system("pause");
return 0;
}
打印
四、TEST_F宏(Test Fixture)
很多时候,我们想在不同的测试执行前,创建相同的配置环境,在测试执行结束后执行相应的清理工作。测试固件(Test Fixture)为这种需求提供了方便。“Fixture”是一个汉语中不易直接对应的词,《美国传统词典》对它的解释是“(作为附属物的)固定装置;被固定的状态”。
在单元测试中,Fixture的作用是为测试创建辅助性的上下文环境,实现测试的初始化和终结与测试过程本身的分离,便于不同测试使用相同代码来搭建固定的配置环境。测试固件体现了对一系列测试(在开始和结束时)的规定动作。
TEST_F主要是进行多样测试,在多种不同情况的测试TestCase中都会使用相同一份的测试数据的时候将会才用它。即相同的数据测试不同的行为,如果采用TEST宏进行测试那么将会为不同的测试case创建多份数据。TEST_F宏将会共用一份避免重复拷贝共具灵活性。
TEST_F语法定义:
TEST_F(test_case_name, test_name);
test_case_name第一个参数是测试用例名,必须取类名。这个和TEST宏不同
test_name 第二个参数是测试名这个随便取,但最好取有意义的名称
使用TEST_F时必须继承::testing::Test类。并且该类提供了两个接口void SetUp(); void TearDown();
用TES_F比单纯调用 TEST宏稍微麻烦一些:
1、从gtest的 testing::Test类派生一个类,用 public或 protected定义以下所有成员。
2、建立环境:使用默认构造函数,或定义一个虚成员函数 virtual void SetUp()。
3、销毁环境:使用析构函数,或定义一个虚成员函数 virtual void TearDown()。
4、用 TEST_F定义测试,写法与 TEST相同,但测试用例名必须为上面定义的类名。
每个带固件的测试的执行顺序是:
1、调用默认构造函数创建一个新的带固件对象。
2、立即调用 SetUp()。
3、运行 TEST_F体。
4、立即调用 TearDown()。
5、调用析构函数销毁类对象。
inline int Add(int i, int j) { return i + j; }
class AddTest : public testing::Test
{
public:
virtual void SetUp() { puts("SetUp()"); }
virtual void TearDown() { puts("TearDown()"); }
};
TEST_F(AddTest, 正数) {
ASSERT_GT(Add(1, 2), 3); // 故意的
ASSERT_EQ(Add(4, 5), 6); // 也是故意的
}
TEST_F(AddTest, 复数) {
ASSERT_GT(Add(2, 2), 3); // 故意的
ASSERT_EQ(Add(8, 5), 6); // 也是故意的
}
int main(int argc, char **argv) {
std::cout << "Running main() from gtest_main.cc\n";
testing::InitGoogleTest(&argc, argv);
RUN_ALL_TESTS();
system("pause");
return 0;
}
五、TEST_P
当待测试方法的行为取决于传入的参数时,而且这些参数的不同组合有多种, 而你又不想为此写多个相类似的test case时,可以用value-parameterized Test
value-parameterized Test 允许你可以使用不同的参数测试代码, 而无需编写同一测试的多个副本
enum class CalculateType : int
{
add = 1,
minus = 2,
plus = 3,
divide = 4
};
class MyClass
{
public:
int calculate(int a, int b, CalculateType type)
{
int c = 0;
switch (type)
{
case CalculateType::add:
c = a + b;
break;
case CalculateType::minus:
c = a - b;
break;
case CalculateType::plus:
c = a * b;
break;
case CalculateType::divide:
c = a / b;
break;
}
return c;
}
};
struct MyTestData
{
int a;
int b;
CalculateType type;
};
class TestMyClass : public ::testing::Test,
public ::testing::WithParamInterface<MyTestData>
{
public:
MyClass myclass;
};
TEST_P(TestMyClass, norml)
{
int a = GetParam().a;
int b = GetParam().b;
int re = myclass.calculate(a, b, GetParam().type);
switch (GetParam().type)
{
case CalculateType::add:
EXPECT_EQ(a + b, re);
break;
case CalculateType::minus:
EXPECT_EQ(a - b, re);
break;
case CalculateType::plus:
EXPECT_EQ(a * b, re);
break;
case CalculateType::divide:
EXPECT_EQ(a / b, re);
break;
}
}
INSTANTIATE_TEST_SUITE_P(TestMyClassParams,TestMyClass, ::testing::Values(
MyTestData{ 1, 2, CalculateType::add },
MyTestData{ 4, 3, CalculateType::minus },
MyTestData{ 5, 6, CalculateType::plus },
MyTestData{ 8, 2, CalculateType::divide }
));
参考:
Gtest入门2 Gtest之TEST宏的用法_sevencheng798的博客-CSDN博客_gtest test宏