测试-GTest入门

首先构建

选择最适合当前编译器版本的GTest。

Linux

官方的构建环境(未测试):gcc 5.0+,CMake

Windows

CMake版本:3.8.0-rc2

  • MSVC2013 -> V1.8.1
  • MSVC2015 -> V1.10
  • 更多未尝试

断言

GTest使用断言(assertion)来测试代码是否符合预期,断言结果分别有:

  • success:成功;
  • non-fatal failture:失败但继续;
  • fatal failture:失败并崩溃(crash)。

GTest提供EXPECT_*ASSERT_*实现断言。

EXPECT_*提供successnon-fatal failture两个结果,在实际单元测试中也更推荐使用。

ASSERT_*提供的successfatal-failture,在出现失败后,程序会直接崩溃,导致内存、文件资源未释放,引发不可预料的问题。

一元比较

ASSERT EXPECT 验证
ASSERT_TRUE(condition) EXPECT_TRUE(condition) condition为真
ASSERT_FALSE(condition) EXPECT_FALSE condition为假

二元比较

Col1 Col2 Col3
ASSERT_EQ(val1, val2) EXPECT_EQ(val1, val2) va1 == val2
ASSERT_NE(val1, val2) EXPECT_NE(val1, val2) val != 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

快速开始

首先,假设需要验证一个数是否为质数,创建函数bool isPrimeNumber(int number);

1
2
// prime.h
bool isPrimeNumber(int number);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// prime.cpp
#include "prime.h"

bool isPrimeNumber(int number)
{
if(number < 2)
return false;

for(int i = 2; i <= sqrt(number) + 1; ++i)
{
if(number % i ==0)
{
return false;
}
}
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// main.cpp
#include "prime.h"

TEST(test1, prime1)
{
EXPECT_TRUE(isPrimeNumber(5));
EXPECT_TRUE(isPrimeNumber(4));
EXPECT_TRUE(isPrimeNumber(3));
}

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

使用testing::InitGooleTest初始化框架,并调用RUN_ALL_TESTS运行所有测试,测试结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[==========] Running 1 tests from 1 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from test1
[ RUN ] test1.prime1 // 运行当前组
D:\\...\main.cpp(7): error: Value of: isPrimeNumber(4)
Actual: false
Expected: true
[ FAILED ]test1.prime1 (2ms)
[----------]1 test from test1 (4 ms total)

[----------]Global test environment tear-down
[==========]1 test from 1 test case ran.
[ PASSED ]1 test, listed below: // 1个test失败
[ FAILED ]test1.prime1 // 失败的test suite及其组

此外,在TEST宏函数中,也是可以完成定义变量之类的操作,比如测试一个MyString的复制构造函数(copy constructor)是否正常:

1
2
3
4
5
6
7
8
constexpr char str[] = "Hello World";

TEST(MyString, CopyConstructor)
{
const MyString s1(str);
const MyString s2;
EXPECT_EQ(0, strcmp(s2.data(), s1.data());
}

TEST_F

GTEST中不仅有简单的断言测试,还有更为高级的text fixture,即TEST_F(TestFixtureName, TestName)

fixture,其为固定的设置,即在测试中为每个TEST都执行一个同样的操作。

当需要测试一个容器的功能时,每次都需要对其进行填充,如果使用TEST,则每次都需要定义一个对象,并对其填充,显得很冗余,繁琐。

TEST_F则可以简化这一过程,他的1st parm TestFixtureName是一个类,需要继承自testing::Test,同时根据需要实现以下两个虚函数:

1
2
virtual void SetUp();               // 在TEST_F执行所有测试案例前运行
virtual void TearDown(); // 在TEST_F运行后

可以类比对象的构造函数和析构函数。这样,同一个TestFixtureName下的每个TEST_F都会先执行SetUp,最后执行TearDwon。
此外,testing::Test还提供了两个static函数:

1
2
static void SetUpTestCase();       // 在第一个TEST之前运行
static void TearDownTestCase(); // 在最后一个TEST之后运行