GTest & GMock

ASSERT_ & EXPECT_

Bool

Fatal assertion Nonfatal assertion Verifies
ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false

Value

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

string

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

注意:“CASE”表明忽略大小写,一个 NULL 指针和空字符串不一样

TEST

下面以 googletest/samples 中的 sample1_unittest.cc 中的 demo 为例,简单介绍下一个简单计算阶乘函数 Factorial 实现如下:

1
2
3
4
5
6
7
8
int Factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}

return result;
}

用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 下面三个 TEST 都是属于同一个 test suite,即 FactorialTest
// 正数为一组
TEST(FactorialTest, Negative) {
EXPECT_EQ(1, Factorial(-5));
EXPECT_EQ(1, Factorial(-1));
EXPECT_GT(Factorial(-10), 0);
}
// 0
TEST(FactorialTest, Zero) {
EXPECT_EQ(1, Factorial(0));
}
// 负数为一组
TEST(FactorialTest, Positive) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}

在 sample1_unittest.cc 的 main 函数中,添加 RUN_ALL_TESTS 函数即可。

1
2
3
4
5
int main(int argc, char **argv) {
printf("Running main() from %s\\n", __FILE__);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

在 TEST 宏函数中,也可以像个普通函数一样,定义变量之类的行为。

比如在 sample2_unittest.cc 中,测试一个自定义类 MyString 的复制构造函数是否表现正常:

1
2
3
4
5
6
7
8
const char kHelloString[] = "Hello, world!";

// 在 TEST 内部,定义变量
TEST(MyString, CopyConstructor) {
const MyString s1(kHelloString);
const MyString s2 = s1;
EXPECT_EQ(0, strcmp(s2.c_string(), kHelloString));
}

TEST_F

下面介绍 gtest 中更为高级的功能:test fixture,对应的宏函数是 TEST_F(TestFixtureName, TestName)。

fixture,其语义是固定的设施,而 test fixture 在 gtest 中的作用就是为每个 TEST 都执行一些同样的操作。

比如,要测试一个队列 Queue 的各个接口功能是否正常,因此就需要向队列中添加元素。如果使用一个 TEST 函数测试 Queue 的一个接口,那么每次执行 TEST 时,都需要在 TEST 宏函数中定义一个 Queue 对象,并向该对象中添加元素,就很冗余、繁琐。

怎么避免这部分冗余的过程?

TEST_F 就是完成这样的事情,它的第一个参数 TestFixtureName 是个类,需要继承 testing::Test,同时根据需要实现以下两个虚函数:

  • virtual void SetUp():在 TEST_F 中测试案例之前运行;
  • virtual void TearDown():在 TEST_F 之后运行。

可以类比对象的构造函数和析构函数。这样,同一个 TestFixtureName 下的每个 TEST_F 都会先执行 SetUp,最后执行 TearDwom。

此外,testing::Test 还提供了两个 static 函数:

  • static void SetUpTestSuite():在第一个 TEST 之前运行
  • static void TearDownTestSuite():在最后一个 TEST 之后运行

以 sample3-inl 中实现的 class Queue 为例:

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 QueueTestSmpl3 : public testing::Test { // 继承了 testing::Test
protected:

static void SetUpTestSuite() {
std::cout<<"run before first case..."<<std::endl;
}

static void TearDownTestSuite() {
std::cout<<"run after last case..."<<std::endl;
}

virtual void SetUp() override {
std::cout<<"enter into SetUp()" <<std::endl;
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}

virtual void TearDown() override {
std::cout<<"exit from TearDown" <<std::endl;
}

static int Double(int n) {
return 2*n;
}

void MapTester(const Queue<int> * q) {
const Queue<int> * const new_q = q->Map(Double);

ASSERT_EQ(q->Size(), new_q->Size());

for (const QueueNode<int>*n1 = q->Head(), *n2 = new_q->Head();
n1 != nullptr; n1 = n1->next(), n2 = n2->next()) {
EXPECT_EQ(2 * n1->element(), n2->element());
}

delete new_q;
}

Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};

下面是 sample3_unittest.cc 中的 TEST_F:

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
// in sample3_unittest.cc

// Tests the default c'tor.
TEST_F(QueueTestSmpl3, DefaultConstructor) {
// !!! 在 TEST_F 中可以使用 QueueTestSmpl3 的成员变量、成员函数
EXPECT_EQ(0u, q0_.Size());
}

// Tests Dequeue().
TEST_F(QueueTestSmpl3, Dequeue) {
int * n = q0_.Dequeue();
EXPECT_TRUE(n == nullptr);

n = q1_.Dequeue();
ASSERT_TRUE(n != nullptr);
EXPECT_EQ(1, *n);
EXPECT_EQ(0u, q1_.Size());
delete n;

n = q2_.Dequeue();
ASSERT_TRUE(n != nullptr);
EXPECT_EQ(2, *n);
EXPECT_EQ(1u, q2_.Size());
delete n;
}

// Tests the Queue::Map() function.
TEST_F(QueueTestSmpl3, Map) {
MapTester(&q0_);
MapTester(&q1_);
MapTester(&q2_);
}

以 TEST_F(QueueTestSmpl3, DefaultConstructor) 为例,再具体讲解下 TEST_F 的运行流程:

  • gtest 构造一个 QueueTestSmpl3 对象 t1;
  • t1.setUp 初始`t1
  • 第一个 TEST_F 即 DefaultConstructor 开始运行并结束
  • t1.TearDwon 运行,用于清理工作

EXPECT_CALL

1
2
3
4
EXPECT_CALL(mock_object, method(matcher))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);
  • 第一行中 (matcher) 是可有可无的,只有存在函数同名重载的情况下,(matcher) 才是必须的,用于匹配入参格式
  • 第二行也是可有可无的,cardinality 表示函数应该被调用的次数。常见的有:Times(n) 应该被调用 n 次;Times(::testing::AtLeast(n)) 至少应该被调用 n 次
  • 第三行和第四行,表示做一次或重复做 action。常见的 action 有::testing::Return(n) 表示返回一个数字

例如:

1
2
3
EXPECT_CALL(mock_if_impl, some_func)
.Times(::testing::AtLeast(1))
.WillOnce(::testing::Return(true));