GTest
简介: google的单元测试框架
tl;dr
1 |
|
有一个被测试的方法, add, 通过TEST添加一个测试案例, 可以使用EXPECT和ASSERT两种宏, 实现测试值是否正确, 每个宏后面都可以跟上解释信息。 其中第二个很明显是错误的, 输出结果看下面。
编译命令g++ file.cpp -lgtest -lgtest_main -lpthread -o main
其中用到了三个动态链接库, 第一个是gtest的库, 第二个是运行所有测试的实现, 其实里面就是写了个main函数, 也可以自己写,不连接这个库, 第三个是多线程库, 因为gtest使用了线程。
运行结果:
可以看到失败的地方会有提示。
基本使用
运行指定测试
--gtest_filter=TestName.*
测试案例宏
TEST — 一个测试案例
原型: TEST(TestCaseName, TestName)
测试的逻辑是, 每个Case为一组, 组内可以有多个Test, 也就是说, 当测试一个类的时候, 可以这么写 Test(TestClassName, FuntionName)
TEST_F
原型:TEST_F(TestFixtureName, TestName)
模具测试 当多个测试使用相同或类似的资源的时候, 可以使用模具进行测试, 需要创建模具类, 在里面创建需要的资源。
SetUp方法和TearDown方法在每次TEST_F执行之前和执行之后执行, 保证每次测试的资源都是没有关联的。
TEST_P
//TODO:后续补充
断言
ASSERT_* – 当条件判断为假时, 不会往下继续执行
ASSERT_EQ(val1, val2)
断言val1和val2相等, 如果不相等会直接终止程序, 并报告错误, 信息里面有当前测试的案例和测试名称, 以及两个值分别是多少。
甚至你可以添加一些输出, 让提示更加友好。
ASSERT_EQ(v1, v2) << "v1 is not equal to v2 , v1 is " << v1 << " v2 is " << v2;
这样当判断不相等是会输出后面的信息。
EXPECT_* – 当条件为假时, 判为faile, 但是会继续向下执行
用法与ASSERT一样, 唯一的区别就是如果断言值为假也会继续向下执行, 只是报告一个失败,下面的测试会继续进行。
同类的宏
每个版本的宏都有两个,分别是EXPECT和ASSERT。 区别如上。
- 大小值比较
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_TRUE(condition);
EXPECT_TRUE(condition);
condition
is trueASSERT_FALSE(condition);
EXPECT_FALSE(condition);
condition
is false字符串比较
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 contents 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 contents, ignoring case
模具的使用
当多个测试使用的数据或对象相同时,可以创建一个模具给这一组测试使用。可以减少重复的代码。
使用步骤
- 首先要创建一个模具类并继承
::testing::Test
- 实现一个构造函数或者
Setup()
, 以及一个析构函数或者TearDown()
- 在构造函数或者
Setup()
方法里面创建一些测试需要的资源。 同理在析构或TearDown
中释放这些资源。
当使用模具进行测试的时候,使用TEST_F
替换TEST
即可, 值得注意的是, 宏的第一个参数要改成自己写的模具类的名字。TEST_F(TestFixtureName, TestName)
即TestFixtureName要替换成模具类的名字。然后在函数体里面进行测试即可。
对于每个测试(TEST_F), gtest都会在测试之前调用Setup为其创建测试环境, 当这个测试结束时会调用TearDown来清理现场。
案例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Foo {
public:
Foo (int a = 0) {}
virtual ~Foo () {}
virtual int getData() { return data_; }
virtual void setData(int data) { data_ = data; }
private:
int data_;
};
class FooTest : public ::testing::Test {
public:
FooTest () { }
virtual ~FooTest () { }
void SetUp() {
std::cout << "Before testing" << std::endl;
foo_.setData(1);
}
void TearDown() {
std::cout << "After the test" << std::endl;
}
protected:
Foo foo_;
};
TEST_F(FooTest, TestSetOne) {
std::cout << "TestSetOne start" << std::endl;
EXPECT_EQ(foo_.getData(), 1) << "foo_ data is not equal to " << 1;
int data = 10;
foo_.setData(data);
EXPECT_EQ(foo_.getData(), data) << "foo_ data is not equal to " << data;
std::cout << "TestSetOne end" << std::endl;
}
TEST_F(FooTest, TestSetTwo) {
std::cout << "TestSetOne start" << std::endl;
EXPECT_EQ(foo_.getData(), 1) << "foo_ data is not equal to " << 1;
std::cout << "TestSetOne end" << std::endl;
}
结果:
如案例中所示, 在夹具中定义的资源可以在测试中直接使用,所以当多个测试使用的资源相同的时候,还有复杂的初始化工作的时候,就可以使用夹具,减少重复代码。
SetUpCase 与 TearDownCase
TODO:后续补充
GMock
简介:
模拟类, 当我们写一个模块时,我们要依赖或使用另一个模块的接口或资源,例如数据库操作等。这时候另一个模块还没有写,我们需要测试一下现在写的模块功能是否正确,这就用到gmock了, 它可以模拟一个类, 可以指定一个行为,通过返回我们指定的数据来欺骗过我们写的模块。 例如我们需要数据库查询一个用户的信息,这时候可以模拟这个方法,直接返回一个固定的信息。
Mock Class
创建一个Mock类需要继承需要模拟的类或者接口。 使用MOCKMETHOD 模拟方法。
MOCKMETHOD
MOCKMETHOD(返回值类型, 方法名, (参数), (override等))
写完一个模块需要单元测试时,依赖的另一个模块还没有做完,那么可以mock这个模块。例如 数据库模块。
参考连接:
- googletest仓库地址 https://github.com/google/googletest