对 GoogleTest(https://github.com/google/googletest)的技术调研。

  1. 编译安装

步骤

1
2
3
4
5
6
git clone https://github.com/google/googletest.git
cd googletest/googletest
mkdir mybuild
cd mybuild
cmake -Dgtest_build_samples=ON ..
make

编译选项

  • -DGTEST_USE_OWN_TR1_TUPLE=1。使用自带的 TR1 Tuple。若使用自己工程的 TR1 Tuple library,须有-DGTEST_USE_OWN_TR1_TUPLE=0
  • -DGTEST_HAS_TR1_TUPLE=0。禁用使用了 TR1 Tuple 的特性。

Some Google Test features require the C++ Technical Report 1 (TR1) tuple library, which is not yet available with all compilers.

  • -DGTEST_HAS_PTHREAD=1。当pthread启用时,GTest 是线程安全的。在#include "gtest/gtest.h"之后检查GTEST_IS_THREADSAFE宏可以判断是否是线程安全的。如果判断不准确,可定义该宏强制启用pthread
  • -DGTEST_CREATE_SHARED_LIBRARY=1。若需要生成动态链接库,添加此选项。
  • -DGTEST_LINKED_AS_SHARED_LIBRARY=1。若要使用动态库编译自己的测试代码,添加此选项。
  • -DGTEST_DONT_DEFINE_XXXXX=1。为防止与已有宏冲突,将 GTest 中的宏XXXXX改为GTEST_XXXXX
  1. 示例代码

Sample 1: 测试函数

  • Step #1: 包含头文件。
1
2
3
#include <limits.h>
#include "sample1.h"
#include "gtest/gtest.h"
  • Step #2: 定义测试。

    • 两个参数:测试用例名 test case name、测试名 test name。
    • 必须是合法 C++ 标识符,不能有下划线_
    • 多个 logically related 的测试组成一个测试用例。
    • 使用在gtest.h中定义的宏来写测试。
    • GTest 保证每个测试做且只做一次,但不保证测试顺序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Tests Factorial().

// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {
EXPECT_EQ(1, Factorial(-5));
EXPECT_EQ(1, Factorial(-1));
EXPECT_GT(Factorial(-10), 0);
}

// Tests factorial of 0.
TEST(FactorialTest, Zero) {
EXPECT_EQ(1, Factorial(0));
}

// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}
  • Step #3:在main()中调用RUN_ALL_TESTS()(甚至不需要注册这些测试),成功则返回 0。

Sample 2: 测试类

  • 一般会为每个类中的方法定义一个测试用例。(当然可按需决定)
  • 使用EXPECT_EQ比较指针和NULL会触发编译器警告。

Sample 3: 使用 test fixture

  • text fixture 是用于保存多个测试间共享的对象和方法。
  • 为了让每个测试 independent and repeatable,每个测试用例分别有这些共享对象的一个拷贝,不会相互影响。
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// To use a test fixture, derive a class from testing::Test.
class QueueTestSmpl3 : public testing::Test {
protected: // You should make the members protected s.t. they can be
// accessed from sub-classes.

// virtual void SetUp() will be called before each test is run. You
// should define it if you need to initialize the variables.
// Otherwise, this can be skipped.
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}

// virtual void TearDown() will be called after each test is run.
// You should define it if there is cleanup work to do. Otherwise,
// you don't have to provide it.
//
// virtual void TearDown() {
// }

// Other helper functions.
// ...

// Declares the variables your tests want to use.
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};


// When you have a test fixture, you define a test using TEST_F
// instead of TEST.

// Tests the default c'tor.
TEST_F(QueueTestSmpl3, DefaultConstructor) {
// You can access data in the test fixture here.
EXPECT_EQ(0u, q0_.Size());
}

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

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

n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
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_);
}

Sample 4: 利用继承在多个用例中复用 test fixture

如要求让所有测试在 5s 内完成。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
class QuickTest : public testing::Test {
protected:
// Remember that SetUp() is run immediately before a test starts.
// This is a good place to record the start time.
virtual void SetUp() {
start_time_ = time(NULL);
}

// TearDown() is invoked immediately after a test finishes. Here we
// check if the test was too slow.
virtual void TearDown() {
// Gets the time when the test finishes
const time_t end_time = time(NULL);

// Asserts that the test took no more than ~5 seconds. Did you
// know that you can use assertions in SetUp() and TearDown() as
// well?
EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long.";
}

// The UTC time (in seconds) when the test starts
time_t start_time_;
};


// We derive a fixture named IntegerFunctionTest from the QuickTest
// fixture. All tests using this fixture will be automatically
// required to be quick.
class IntegerFunctionTest : public QuickTest {
// We don't need any more logic than already in the QuickTest fixture.
// Therefore the body is empty.
};

// Tests Factorial()
TEST_F(IntegerFunctionTest, Factorial) {
// Tests factorial of negative numbers.
EXPECT_EQ(1, Factorial(-5));
EXPECT_EQ(1, Factorial(-1));
EXPECT_GT(Factorial(-10), 0);

// Tests factorial of 0.
EXPECT_EQ(1, Factorial(0));

// Tests factorial of positive numbers.
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}

// The next test case (named "QueueTest") also needs to be quick, so
// we derive another fixture from QuickTest.
//
// The QueueTest test fixture has some logic and shared objects in
// addition to what's in QuickTest already. We define the additional
// stuff inside the body of the test fixture, as usual.
class QueueTest : public QuickTest {
protected:
virtual void SetUp() {
// First, we need to set up the super fixture (QuickTest).
QuickTest::SetUp();

// Second, some additional setup for this fixture.
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}

// By default, TearDown() inherits the behavior of
// QuickTest::TearDown(). As we have no additional cleaning work
// for QueueTest, we omit it here.
//
// virtual void TearDown() {
// QuickTest::TearDown();
// }

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


// Tests the default constructor.
TEST_F(QueueTest, DefaultConstructor) {
EXPECT_EQ(0u, q0_.Size());
}

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

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

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

Sample 5:

Sample 6: 利用模板进行接口测试

两种方式:

  • “typed tests”:知道所有的要测试的派生类。
  • “type-parameterized tests”:

Sample 7: ::testing::TestWithParam