Googletest advanced学习


看了一下Advanced googletest Topics,稍微整理了一下,主要讲了一些用得不是特别多,但是也很重要的assertions。我找了一篇博客,借用了他的代码来进行测试。

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
#include <gtest/gtest.h>

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}
));

代码如上,执行后结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[==========] Running 4 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 4 tests from TestMyClassParams/TestMyClass
[ RUN ] TestMyClassParams/TestMyClass.norml/0
[ OK ] TestMyClassParams/TestMyClass.norml/0 (0 ms)
[ RUN ] TestMyClassParams/TestMyClass.norml/1
[ OK ] TestMyClassParams/TestMyClass.norml/1 (0 ms)
[ RUN ] TestMyClassParams/TestMyClass.norml/2
[ OK ] TestMyClassParams/TestMyClass.norml/2 (0 ms)
[ RUN ] TestMyClassParams/TestMyClass.norml/3
[ OK ] TestMyClassParams/TestMyClass.norml/3 (0 ms)
[----------] 4 tests from TestMyClassParams/TestMyClass (0 ms total)

[----------] Global test environment tear-down
[==========] 4 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 4 tests.

接下来的assertions我会在上方的代码中尝试。

Explicit Success and Failure

这个断言会显示表达成功或者失败。感觉Success这个断言非常鸡肋,因为某处Success并没有什么用,要的是执行完所有的代码都是Success,文档也说目前Success也不会有什么用户可以看到的输出。但是Failure就显然有用得多。

Failure分为几种:

FAIL()

立刻停止当前测试,并输出错误。值得注意的是,它只能用于返回值为void的函数。

在上面的代码中,我稍作修改,给div操作加了一个除0错误,检测到除数为0抛出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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:
if(abs(b - 0) > 1e-7){
FAIL() << "div 0 error!";
}
EXPECT_EQ(a / b, re);
break;
}
}

并在测试集中加入:

1
MyTestData{8, 0, CalculateType::divide}

输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Running main() from /Users/bytedance/Desktop/googletest/googletest/src/gtest_main.cc
[==========] Running 5 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 5 tests from TestMyClassParams/TestMyClass
[ RUN ] TestMyClassParams/TestMyClass.norml/0
[ OK ] TestMyClassParams/TestMyClass.norml/0 (0 ms)
[ RUN ] TestMyClassParams/TestMyClass.norml/1
[ OK ] TestMyClassParams/TestMyClass.norml/1 (0 ms)
[ RUN ] TestMyClassParams/TestMyClass.norml/2
[ OK ] TestMyClassParams/TestMyClass.norml/2 (0 ms)
[ RUN ] TestMyClassParams/TestMyClass.norml/3
test_p.cpp:71: Failure
Failed
div 0 error!
[ FAILED ] TestMyClassParams/TestMyClass.norml/3, where GetParam() = 12-byte object <08-00 00-00 02-00 00-00 04-00 00-00> (0 ms)
[ RUN ] TestMyClassParams/TestMyClass.norml/4
[1] 19556 floating point exception ./test

可以看到测试确实fail了。

ADD_FAILURE()

FAIL()一旦出现,就会中止当前测试,像上面的除0错误就是致命错误。而ADD_FAILURE()则是非致命错误,打上标签可以继续运行。

在这里假设我们预期的操作数都是正数,如果是负数就抛出一个非致命错误。

将测试代码改为:

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
TEST_P(TestMyClass, norml)
{
int a = GetParam().a;
int b = GetParam().b;
if(a < 0 || b < 0){
ADD_FAILURE() << "operator should be positive!";
std::cout << "I am fail" << std::endl;
}
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;
}
}

在标志为失败后输出”I am fail”,并将第四个样例改为:

1
MyTestData{8, -2, CalculateType::divide}

输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
Running main() from /Users/bytedance/Desktop/googletest/googletest/src/gtest_main.cc
[==========] Running 4 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 4 tests from TestMyClassParams/TestMyClass
[ RUN ] TestMyClassParams/TestMyClass.norml/0
[ OK ] TestMyClassParams/TestMyClass.norml/0 (0 ms)
...
[ RUN ] TestMyClassParams/TestMyClass.norml/3
test_p.cpp:58: Failure
Failed
operator should be positive!
I am fail
...

可以看到输出了”I am fail”。

如果把上面的ADD_FAILURE()改为FAIL(),则会输出:

1
2
3
4
5
6
7
8
9
10
[==========] Running 4 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 4 tests from TestMyClassParams/TestMyClass
[ RUN ] TestMyClassParams/TestMyClass.norml/0
...
test_p.cpp:58: Failure
Failed
operator should be positive!
[ FAILED ] TestMyClassParams/TestMyClass.norml/3, where GetParam() = 12-byte object <08-00 00-00 FE-FF FF-FF 04-00 00-00> (0 ms)
...

这说明FAIL()会中止当前测试,而ADD_FAILURE()不会。

ADD_FAILURE_AT

1
ADD_FAILURE_AT(`*`file_path`*`,`*`line_number`*`)

感觉这个和ADD_FAILURE差不多,就是会把文件的路径和行数也一起输出,方便定位错误。

Exception Assertions

这个系列断言与异常相关。感觉比较简单,格式如下:

1
2
3
4
EXPECT_NO_THROW({
int n = 5;
DoSomething(&n);
});

EXPECT_THROW

1
2
EXPECT_THROW(statement,exception_type)
ASSERT_THROW(statement,exception_type)

这样得保证statement得抛出exception_type类型的异常

EXPECT_ANY_THROW

1
2
EXPECT_ANY_THROW(statement)
ASSERT_ANY_THROW(statement)

得保证statement抛出任意异常

EXPECT_NO_THROW

1
2
EXPECT_NO_THROW(statement)
ASSERT_NO_THROW(statement)

保证statement不会抛出异常

Predicate Assertions

这个东西感觉就是来替代EXPECT_TRUE的。

EXPECT_PRED*

样例的用法如下:

1
2
3
4
5
6
7
8
9
// Returns true if m and n have no common divisors except 1.
bool MutuallyPrime(int m, int n) { ... }
...
const int a = 3;
const int b = 4;
const int c = 10;
...
EXPECT_PRED2(MutuallyPrime, a, b); // Succeeds
EXPECT_PRED2(MutuallyPrime, b, c); // Fails

可以通过修改EXPECT_PRED后面的数字来决定函数后有几个参数,但是我实际运行的时候出现了编译错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
error: no matching function for call to 'AssertPred2Helper'
EXPECT_PRED2(equal, a, re);
^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/gtest/gtest_pred_impl.h:165:3: note: expanded from macro 'EXPECT_PRED2'
GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/gtest/gtest_pred_impl.h:154:17: note: expanded from macro 'GTEST_PRED2_'
GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/gtest/gtest_pred_impl.h:76:52: note: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^~~~~~~~~~
/usr/local/include/gtest/gtest_pred_impl.h:129:17: note: candidate template ignored: couldn't infer template argument 'Pred'
AssertionResult AssertPred2Helper(const char* pred_text,
^
1 error generated.

仔细看了半天文档,发现应该这么做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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_PRED2(static_cast<bool (*)(int, int)>(equal), 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;
}
}

如同在CalculateType::add这个case里用一个static_cast来进行转换。这样可以顺利地通过测试。

EXPECT_PRED*()虽然可以很好的完成预期,但是这个语法不怎么通用,对不同参数的函数需要用不同的宏,比较麻烦。因此用::testing::AssertionResult类来解决这个问题。并且可以用<<符号来决定输出错误信息。

根据样例写了个代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <gtest/gtest.h>

testing::AssertionResult IsEven(int n) {
if ((n % 2) == 0)
return testing::AssertionSuccess() << n << "is even";
else
return testing::AssertionFailure() << n << " is odd";
}
TEST(Even, HandlesZeroInput) {
EXPECT_TRUE(IsEven(100));
EXPECT_FALSE(IsEven(100));
}


int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

编译后输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from Even
[ RUN ] Even.HandlesZeroInput
test5.cpp:12: Failure
Value of: IsEven(100)
Actual: true (100is even)
Expected: false
[ FAILED ] Even.HandlesZeroInput (0 ms)
[----------] 1 test from Even (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] Even.HandlesZeroInput

1 FAILED TEST

还可以结合EXPECT_PRED_FORMAT*,其参数列表有两组,一组是参数在代码中的字符串表示,一组是参数的值。具体用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <gtest/gtest.h>

testing::AssertionResult IsEven(const char* n_expr, int n) {
if ((n % 2) == 0)
return testing::AssertionSuccess() << n_expr << "is even";
else
return testing::AssertionFailure() << n_expr << " is odd";
}
TEST(Even, HandlesZeroInput) {
int x = 101;
EXPECT_PRED_FORMAT1(IsEven, x);
}


int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

输出如下:

1
2
3
4
5
6
7
8
9
$ ./test5                                                         
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from Even
[ RUN ] Even.HandlesZeroInput
test5.cpp:12: Failure
x is odd
...

这样就可以看到对应的变量x导致的错误。