C++单元测试框架Google Test系列(gtest)

mac2025-07-14  10

目录

1. 前言

2. 断言

示例

操作符<<

布尔值检查

数值型数据检查

字符串检查

显示返回成功或失败

异常检查

Predicate Assertions

浮点型检查

类型检查

3. 事件机制

全局事件

TestSuite事件

TestCase事件

4. 参数化

旧方案

使用参数化后的方案

参数化后的测试案例名

类型参数化

5. 死亡测试

*_DEATH(statement, regex`)

*_EXIT(statement, predicate, regex`)

*_DEBUG_DEATH

死亡测试运行方式

注意事项

总结

6. 运行参数

基本介绍

参数列表

测试案例集合

测试案例输出

对案例的异常处理

XML报告输出格式


1. 前言

偶然间碰到一个GTEST 总结很好的文章,这里搬运过来,以后可以作为一个参考。

 

2. 断言

1. ASSERT_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)。

2. EXPECT_* 系列的断言,当检查点失败时,继续往下执行。

示例

// int型比较,预期值:3,实际值:Add(1, 2) EXPECT_EQ(3, Add(1, 2)) //

假如你的Add(1, 2) 结果为4的话,会在结果中输出:

g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp(16): error: Value of: Add(1, 2) Actual: 4 Expected:3

如果是将结果输出到xml里的话,将输出:

<testcase name="Demo" status="run" time="0" classname="AddTest"> <failure message="Value of: Add(1, 2) Actual: 4 Expected: 3" type=""><![CDATA[g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp:16 Value of: Add(1, 2) Actual: 4 Expected: 3]]></failure> </testcase

 

操作符<<

如果你对自动输出的出错信息不满意的话,你还可以通过操作符<<将一些自定义的信息输出,通常,这对于调试或是对一些检查点的补充说明来说,非常有用!

如果不使用<<操作符自定义输出的话:

for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]); }

看到的结果将是这样的,你根本不知道出错时 i 等于几:

g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp(25): error: Value of: y[i] Actual: 4 Expected: x[i] Which is: 3

如果使用<<操作符将一些重要信息输出的话:

for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; }

从输出结果中就可以定位到在 i = 2 时出现了错误。这样的输出结果看起来更加有用,容易理解:

g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp(25): error: Value of: y[i] Actual: 4 Expected: x[i] Which is: 3 Vectors x and y differ at index 2

 

布尔值检查

Fatal assertionNonfatal assertionVerifiesASSERT_TRUE(condition);EXPECT_TRUE(condition);condition is trueASSERT_FALSE(condition);EXPECT_FALSE(condition);condition is false

数值型数据检查

Fatal assertionNonfatal assertionVerifiesASSERT_EQ(expected, actual);EXPECT_EQ(expected, actual);expected == actualASSERT_NE(val1, val2);EXPECT_NE(val1, val2);val1 != val2ASSERT_LT(val1, val2);EXPECT_LT(val1, val2);val1 < val2ASSERT_LE(val1, val2);EXPECT_LE(val1, val2);val1 <= val2ASSERT_GT(val1, val2);EXPECT_GT(val1, val2);val1 > val2ASSERT_GE(val1, val2);EXPECT_GE(val1, val2);val1 >= val2

字符串检查

Fatal assertionNonfatal assertionVerifiesASSERT_STREQ(expected_str, actual_str);EXPECT_STREQ(expected_str, actual_str);the two C strings have the same contentASSERT_STRNE(str1, str2);EXPECT_STRNE(str1, str2);the two C strings have different contentASSERT_STRCASEEQ(expected_str, actual_str);EXPECT_STRCASEEQ(expected_str, actual_str);the two C strings have the same content, ignoring caseASSERT_STRCASENE(str1, str2);EXPECT_STRCASENE(str1, str2);the two C strings have different content, ignoring case

*STREQ*和*STRNE*同时支持char*和wchar_t*类型的,*STRCASEEQ*和*STRCASENE*却只接收char*,估计是不常用吧。下面是几个例子:

TEST(StringCmpTest, Demo) { char* pszCoderZh = "CoderZh"; wchar_t* wszCoderZh = L"CoderZh"; std::string strCoderZh = "CoderZh"; std::wstring wstrCoderZh = L"CoderZh"; EXPECT_STREQ("CoderZh", pszCoderZh); EXPECT_STREQ(L"CoderZh", wszCoderZh); EXPECT_STRNE("CnBlogs", pszCoderZh); EXPECT_STRNE(L"CnBlogs", wszCoderZh); EXPECT_STRCASEEQ("coderzh", pszCoderZh); //EXPECT_STRCASEEQ(L"coderzh", wszCoderZh); 不支持 EXPECT_STREQ("CoderZh", strCoderZh.c_str()); EXPECT_STREQ(L"CoderZh", wstrCoderZh.c_str()); }

显示返回成功或失败

直接返回成功:SUCCEED();

返回失败:

Fatal assertionNonfatal assertionFAIL();ADD_FAILURE(); TEST(ExplicitTest, Demo) { ADD_FAILURE() << "Sorry"; // None Fatal Asserton,继续往下执行。 //FAIL(); // Fatal Assertion,不往下执行该案例。 SUCCEED(); }

异常检查

Fatal assertionNonfatal assertionVerifiesASSERT_THROW(statement, exception_type);EXPECT_THROW(statement, exception_type);statement throws an exception of the given typeASSERT_ANY_THROW(statement);EXPECT_ANY_THROW(statement);statement throws an exception of any typeASSERT_NO_THROW(statement);EXPECT_NO_THROW(statement);statement doesn't throw any exception int Foo(int a, int b) { if (a == 0 || b == 0) { throw "don't do that"; } int c = a % b; if (c == 0) return b; return Foo(b, c); } TEST(FooTest, HandleZeroInput) { EXPECT_ANY_THROW(Foo(10, 0)); EXPECT_THROW(Foo(0, 5), char*); }

Predicate Assertions

在使用EXPECT_TRUE或ASSERT_TRUE时,有时希望能够输出更加详细的信息,比如检查一个函数的返回值TRUE还是FALSE时,希望能够输出传入的参数是什么,以便失败后好跟踪。因此提供了如下的断言:

Fatal assertionNonfatal assertionVerifiesASSERT_PRED1(pred1, val1);EXPECT_PRED1(pred1, val1);pred1(val1) returns trueASSERT_PRED2(pred2, val1, val2);EXPECT_PRED2(pred2, val1, val2);pred2(val1, val2) returns true.........

Google人说了,他们只提供<=5个参数的,如果需要测试更多的参数,直接告诉他们。下面看看这个东西怎么用。

bool MutuallyPrime(int m, int n) { return Foo(m , n) > 1; } TEST(PredicateAssertionTest, Demo) { int m = 5, n = 6; EXPECT_PRED2(MutuallyPrime, m, n); }

当失败时,返回错误信息:

error: MutuallyPrime(m, n) evaluates to false, where m evaluates to 5 n evaluates to 6

如果对这样的输出不满意的话,还可以自定义输出格式,通过如下:

Fatal assertionNonfatal assertionVerifiesASSERT_PRED_FORMAT1(pred_format1, val1);`EXPECT_PRED_FORMAT1(pred_format1, val1);pred_format1(val1) is successfulASSERT_PRED_FORMAT2(pred_format2, val1, val2);EXPECT_PRED_FORMAT2(pred_format2, val1, val2);pred_format2(val1, val2) is successful......... testing::AssertionResult AssertFoo(const char* m_expr, const char* n_expr, const char* k_expr, int m, int n, int k) { if (Foo(m, n) == k) return testing::AssertionSuccess(); testing::Message msg; msg << m_expr << " 和 " << n_expr << " 的最大公约数应该是:" << Foo(m, n) << " 而不是:" << k_expr; return testing::AssertionFailure(msg); } TEST(AssertFooTest, HandleFail) { EXPECT_PRED_FORMAT3(AssertFoo, 3, 6, 2); }

失败时,输出信息:

error: 3 和 6 的最大公约数应该是:3 而不是:2

是不是更温馨呢,呵呵。

浮点型检查

Fatal assertionNonfatal assertionVerifiesASSERT_FLOAT_EQ(expected, actual);EXPECT_FLOAT_EQ(expected, actual);the two float values are almost equalASSERT_DOUBLE_EQ(expected, actual);EXPECT_DOUBLE_EQ(expected, actual);the two double values are almost equal

对相近的两个数比较:

Fatal assertionNonfatal assertionVerifiesASSERT_NEAR(val1, val2, abs_error);EXPECT_NEAR(val1, val2, abs_error);the difference between val1 and val2 doesn't exceed the given absolute error

同时,还可以使用:

EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2); EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2);

类型检查

类型检查失败时,直接导致代码编不过,难得用处就在这?看下面的例子:

template <typename T> class FooType { public: void Bar() { testing::StaticAssertTypeEq<int, T>(); } }; TEST(TypeAssertionTest, Demo) { FooType<bool> fooType; fooType.Bar(); }

 

3. 事件机制

gtest提供了多种事件机制,非常方便我们在案例之前或之后做一些操作。总结一下gtest的事件一共有3种:

1. 全局的,所有案例执行前后。

2. TestSuite级别的,在某一批案例中第一个案例前,最后一个案例执行后。

3. TestCase级别的,每个TestCase前后。

全局事件

要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。

1. SetUp()方法在所有案例执行前执行

2. TearDown()方法在所有案例执行后执行

class FooEnvironment : public testing::Environment { public: virtual void SetUp() { std::cout << "Foo FooEnvironment SetUP" << std::endl; } virtual void TearDown() { std::cout << "Foo FooEnvironment TearDown" << std::endl; } };

当然,这样还不够,我们还需要告诉gtest添加这个全局事件,我们需要在main函数中通过testing::AddGlobalTestEnvironment方法将事件挂进来,也就是说,我们可以写很多个这样的类,然后将他们的事件都挂上去。

int _tmain(int argc, _TCHAR* argv[]) { testing::AddGlobalTestEnvironment(new FooEnvironment); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }

TestSuite事件

我们需要写一个类,继承testing::Test,然后实现两个静态方法

1. SetUpTestCase() 方法在第一个TestCase之前执行 2. TearDownTestCase() 方法在最后一个TestCase之后执行 class FooTest : public testing::Test { protected: static void SetUpTestCase() { shared_resource_ = new ; } static void TearDownTestCase() { delete shared_resource_; shared_resource_ = NULL; } // Some expensive resource shared by all tests. static T* shared_resource_; }; 在编写测试案例时,我们需要使用TEST_F这个宏,第一个参数必须是我们上面类的名字,代表一个TestSuite。 TEST_F(FooTest, Test1) { // you can refer to shared_resource here } TEST_F(FooTest, Test2) { // you can refer to shared_resource here }

TestCase事件

TestCase事件是挂在每个案例执行前后的,实现方式和上面的几乎一样,不过需要实现的是SetUp方法和TearDown方法:

1. SetUp()方法在每个TestCase之前执行

2. TearDown()方法在每个TestCase之后执行

class FooCalcTest:public testing::Test { protected: virtual void SetUp() { m_foo.Init(); } virtual void TearDown() { m_foo.Finalize(); } FooCalc m_foo; }; TEST_F(FooCalcTest, HandleNoneZeroInput) { EXPECT_EQ(4, m_foo.Calc(12, 16)); } TEST_F(FooCalcTest, HandleNoneZeroInput_Error) { EXPECT_EQ(5, m_foo.Calc(12, 16)); }

 

4. 参数化

旧方案

// Returns true iff n is a prime number. bool IsPrime(int n) { // Trivial case 1: small numbers if (n <= 1) return false; // Trivial case 2: even numbers if (n % 2 == 0) return n == 2; // Now, we have that n is odd and n >= 3. // Try to divide n by every odd number i, starting from 3 for (int i = 3; ; i += 2) { // We only have to try i up to the squre root of n if (i > n/i) break; // Now, we have i <= n/i < n. // If n is divisible by i, n is not prime. if (n % i == 0) return false; } // n has no integer factor in the range (1, n), and thus is prime. return true; }

假如我要编写判断结果为True的测试案例,我需要传入一系列数值让函数IsPrime去判断是否为True(当然,即使传入再多值也无法确保函数正确,呵呵),因此我需要这样编写如下的测试案例:

TEST(IsPrimeTest, HandleTrueReturn) { EXPECT_TRUE(IsPrime(3)); EXPECT_TRUE(IsPrime(5)); EXPECT_TRUE(IsPrime(11)); EXPECT_TRUE(IsPrime(23)); EXPECT_TRUE(IsPrime(17)); }

我们注意到,在这个测试案例中,我至少复制粘贴了4次,假如参数有50个,100个,怎么办?同时,上面的写法产生的是1个测试案例,里面有5个检查点,假如我要把5个检查变成5个单独的案例,将会更加累人。

接下来,就来看看gtest是如何为我们解决这些问题的。

使用参数化后的方案

1. 告诉gtest你的参数类型是什么

你必须添加一个类,继承testing::TestWithParam<T>,其中T就是你需要参数化的参数类型,比如上面的例子,我需要参数化一个int型的参数

class IsPrimeParamTest : public::testing::TestWithParam<int> { };

2. 告诉gtest你拿到参数的值后,具体做些什么样的测试

这里,我们要使用一个新的宏(嗯,挺兴奋的):TEST_P,关于这个"P"的含义,Google给出的答案非常幽默,就是说你可以理解为”parameterized" 或者 "pattern"。我更倾向于 ”parameterized"的解释,呵呵。在TEST_P宏里,使用GetParam()获取当前的参数的具体值。

TEST_P(IsPrimeParamTest, HandleTrueReturn) { int n = GetParam(); EXPECT_TRUE(IsPrime(n)); }

3. 告诉gtest你想要测试的参数范围是什么

使用INSTANTIATE_TEST_CASE_P这宏来告诉gtest你要测试的参数范围:

INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));

第一个参数是测试案例的前缀,可以任意取。

第二个参数是测试案例的名称,需要和之前定义的参数化的类的名称相同,如:IsPrimeParamTest

第三个参数是可以理解为参数生成器,上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数:

Range(begin, end[, step])范围在begin~end之间,步长为step,不包括endValues(v1, v2, ..., vN)v1,v2到vN的值ValuesIn(container) and ValuesIn(begin, end)从一个C类型的数组或是STL容器,或是迭代器中取值Bool()取false 和 true 两个值Combine(g1, g2, ..., gN)

这个比较强悍,它将g1,g2,...gN进行排列组合,g1,g2,...gN本身是一个参数生成器,每次分别从g1,g2,..gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。

说明:这个功能只在提供了<tr1/tuple>头的系统中有效。gtest会自动去判断是否支持tr/tuple,如果你的系统确实支持,而gtest判断错误的话,你可以重新定义宏GTEST_HAS_TR1_TUPLE=1。

参数化后的测试案例名

因为使用了参数化的方式执行案例,我非常想知道运行案例时,每个案例名称是如何命名的。我执行了上面的代码,输出如下:

从上面的框框中的案例名称大概能够看出案例的命名规则,对于需要了解每个案例的名称的我来说,这非常重要。 命名规则大概为:

prefix/test_case_name.test.name/index

类型参数化

gtest还提供了应付各种不同类型的数据时的方案,以及参数化类型的方案。我个人感觉这个方案有些复杂。首先要了解一下类型化测试,就用gtest里的例子了。

首先定义一个模版类,继承testing::Test:

template <typename T> class FooTest : public testing::Test { public: ... typedef std::list<T> List; static T shared_; T value_; };

接着我们定义需要测试到的具体数据类型,比如下面定义了需要测试char,int和unsigned int :

typedef testing::Types<char, int, unsigned int> MyTypes; TYPED_TEST_CASE(FooTest, MyTypes);

又是一个新的宏,来完成我们的测试案例,在声明模版的数据类型时,使用TypeParam

TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us to visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the 'TestFixture::' // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the 'typename TestFixture::' // prefix. The 'typename' is required to satisfy the compiler. typename TestFixture::List values; values.push_back(n); ... }

上面的例子看上去也像是类型的参数化,但是还不够灵活,因为需要事先知道类型的列表。gtest还提供一种更加灵活的类型参数化的方式,允许你在完成测试的逻辑代码之后再去考虑需要参数化的类型列表,并且还可以重复的使用这个类型列表。下面也是官方的例子:

template <typename T> class FooTest : public testing::Test { ... }; TYPED_TEST_CASE_P(FooTest);

接着又是一个新的宏TYPED_TEST_P类完成我们的测试案例:

TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; ... } TYPED_TEST_P(FooTest, HasPropertyA) { ... }

接着,我们需要我们上面的案例,使用REGISTER_TYPED_TEST_CASE_P宏,第一个参数是testcase的名称,后面的参数是test的名称

REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA);

接着指定需要的类型列表:

typedef testing::Types<char, int, unsigned int> MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

这种方案相比之前的方案提供更加好的灵活度,当然,框架越灵活,复杂度也会随之增加。

 

5. 死亡测试

“死亡测试”名字比较恐怖,这里的“死亡”指的的是程序的崩溃。通常在测试过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序崩溃,这时我们就需要检查程序是否按照预期的方式挂掉,这也就是所谓的“死亡测试”。gtest的死亡测试能做到在一个安全的环境下执行崩溃的测试案例,同时又对崩溃结果进行验证。

Fatal assertionNonfatal assertionVerifiesASSERT_DEATH(statement, regex`);EXPECT_DEATH(statement, regex`);statement crashes with the given errorASSERT_EXIT(statement, predicate, regex`);EXPECT_EXIT(statement, predicate, regex`);statement exits with the given error and its exit code matches predicate

*_DEATH(statement, regex`)

1. statement是被测试的代码语句

2. regex是一个正则表达式,用来匹配异常时在stderr中输出的内容

如下面的例子:

void Foo() { int *pInt = 0; *pInt = 42 ; } TEST(FooDeathTest, Demo) { EXPECT_DEATH(Foo(), ""); }

重要:编写死亡测试案例时,TEST的第一个参数,即testcase_name,请使用DeathTest后缀。原因是gtest会优先运行死亡测试案例,应该是为线程安全考虑。

*_EXIT(statement, predicate, regex`)

1. statement是被测试的代码语句

2. predicate 在这里必须是一个委托,接收int型参数,并返回bool。只有当返回值为true时,死亡测试案例才算通过。gtest提供了一些常用的predicate:

testing::ExitedWithCode(exit_code)

如果程序正常退出并且退出码与exit_code相同则返回 true

testing::KilledBySignal(signal_number) // Windows下不支持

如果程序被signal_number信号kill的话就返回true

3. regex是一个正则表达式,用来匹配异常时在stderr中输出的内容

这里, 要说明的是,*_DEATH其实是对*_EXIT进行的一次包装,*_DEATH的predicate判断进程是否以非0退出码退出或被一个信号杀死。

例子:

TEST(ExitDeathTest, Demo) { EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); }

*_DEBUG_DEATH

#ifdef NDEBUG #define EXPECT_DEBUG_DEATH(statement, regex) \ do { statement; } while (false) #define ASSERT_DEBUG_DEATH(statement, regex) \ do { statement; } while (false) #else #define EXPECT_DEBUG_DEATH(statement, regex) \ EXPECT_DEATH(statement, regex) #define ASSERT_DEBUG_DEATH(statement, regex) \ ASSERT_DEATH(statement, regex) #endif // NDEBUG for EXPECT_DEBUG_DEATH

可以看到,在Debug版和Release版本下, *_DEBUG_DEATH的定义不一样。因为很多异常只会在Debug版本下抛出,而在Realease版本下不会抛出,所以针对Debug和Release分别做了不同的处理。看gtest里自带的例子就明白了:

int DieInDebugElse12(int* sideeffect) { if (sideeffect) *sideeffect = 12; #ifndef NDEBUG GTEST_LOG_(FATAL, "debug death inside DieInDebugElse12()"); #endif // NDEBUG return 12; } TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { int sideeffect = 0; // Only asserts in dbg. EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death"); #ifdef NDEBUG // opt-mode has sideeffect visible. EXPECT_EQ(12, sideeffect); #else // dbg-mode no visible sideeffect. EXPECT_EQ(0, sideeffect); #endif }

死亡测试运行方式

1. fast方式(默认的方式)

testing::FLAGS_gtest_death_test_style = "fast";

2. threadsafe方式

testing::FLAGS_gtest_death_test_style = "threadsafe";

你可以在 main() 里为所有的死亡测试设置测试形式,也可以为某次测试单独设置。Google Test会在每次测试之前保存这个标记并在测试完成后恢复,所以你不需要去管这部分工作 。如:

TEST(MyDeathTest, TestOne) { testing::FLAGS_gtest_death_test_style = "threadsafe"; // This test is run in the "threadsafe" style: ASSERT_DEATH(ThisShouldDie(), ""); } TEST(MyDeathTest, TestTwo) { // This test is run in the "fast" style: ASSERT_DEATH(ThisShouldDie(), ""); } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); testing::FLAGS_gtest_death_test_style = "fast"; return RUN_ALL_TESTS(); }

注意事项

1. 不要在死亡测试里释放内存。

2. 在父进程里再次释放内存。

3. 不要在程序中使用内存堆检查。

总结

关于死亡测试,gtest官方的文档已经很详细了,同时在源码中也有大量的示例。如想了解更多的请参考官方的文档,或是直接看gtest源码。

简单来说,通过*_DEATH(statement, regex`)和*_EXIT(statement, predicate, regex`),我们可以非常方便的编写导致崩溃的测试案例,并且在不影响其他案例执行的情况下,对崩溃案例的结果进行检查。

 

6. 运行参数

使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便。同时,gtest也为我们提供了一系列的运行参数(环境变量、命令行参数或代码里指定),使得我们可以对案例的执行进行一些有效的控制。

基本介绍

前面提到,对于运行参数,gtest提供了三种设置的途径:

1. 系统环境变量

2. 命令行参数

3. 代码中指定FLAG

因为提供了三种途径,就会有优先级的问题, 有一个原则是,最后设置的那个会生效。不过总结一下,通常情况下,比较理想的优先级为:

命令行参数 > 代码中指定FLAG > 系统环境变量

为什么我们编写的测试案例能够处理这些命令行参数呢?是因为我们在main函数中,将命令行参数交给了gtest,由gtest来搞定命令行参数的问题。

int _tmain(int argc, _TCHAR* argv[]) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }

这样,我们就拥有了接收和响应gtest命令行参数的能力。如果需要在代码中指定FLAG,可以使用testing::GTEST_FLAG这个宏来设置。比如相对于命令行参数--gtest_output,可以使用testing::GTEST_FLAG(output) = "xml:";来设置。注意到了,不需要加--gtest前缀了。同时,推荐将这句放置InitGoogleTest之前,这样就可以使得对于同样的参数,命令行参数优先级高于代码中指定。

int _tmain(int argc, _TCHAR* argv[]) { testing::GTEST_FLAG(output) = "xml:"; testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }

最后再来说下第一种设置方式-系统环境变量。如果需要gtest的设置系统环境变量,必须注意的是:

1. 系统环境变量全大写,比如对于--gtest_output,响应的系统环境变量为:GTEST_OUTPUT

2.  有一个命令行参数例外,那就是--gtest_list_tests,它是不接受系统环境变量的。(只是用来罗列测试案例名称)

参数列表

了解了上面的内容,我这里就直接将所有命令行参数总结和罗列一下。如果想要获得详细的命令行说明,直接运行你的案例,输入命令行参数:/? 或 --help 或 -help

测试案例集合

命令行参数说明--gtest_list_tests使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表。--gtest_filter

对执行的测试案例进行过滤,支持通配符

?    单个字符

*    任意字符

-    排除,如,-a 表示除了a

:    取或,如,a:b 表示a或b

比如下面的例子:

./foo_test 没有指定过滤条件,运行所有案例 ./foo_test --gtest_filter=* 使用通配符*,表示运行所有案例 ./foo_test --gtest_filter=FooTest.* 运行所有“测试案例名称(testcase_name)”为FooTest的案例 ./foo_test --gtest_filter=*Null*:*Constructor* 运行所有“测试案例名称(testcase_name)”或“测试名称(test_name)”包含Null或Constructor的案例。 ./foo_test --gtest_filter=-*DeathTest.* 运行所有非死亡测试案例。 ./foo_test --gtest_filter=FooTest.*-FooTest.Bar 运行所有“测试案例名称(testcase_name)”为FooTest的案例,但是除了FooTest.Bar这个案例

--gtest_also_run_disabled_tests

执行案例时,同时也执行被置为无效的测试案例。关于设置测试案例无效的方法为:

在测试案例名称或测试名称中添加DISABLED前缀,比如:

 

// Tests that Foo does Abc. TEST(FooTest, DISABLED_DoesAbc) {  } class DISABLED_BarTest : public testing::Test {  }; // Tests that Bar does Xyz. TEST_F(DISABLED_BarTest, DoesXyz) {  }

 

--gtest_repeat=[COUNT]

设置案例重复运行次数,非常棒的功能!比如:

--gtest_repeat=1000      重复执行1000次,即使中途出现错误。 --gtest_repeat=-1          无限次数执行。。。。 --gtest_repeat=1000 --gtest_break_on_failure     重复执行1000次,并且在第一个错误发生时立即停止。这个功能对调试非常有用。 --gtest_repeat=1000 --gtest_filter=FooBar     重复执行1000次测试案例名称为FooBar的案例。

测试案例输出

命令行参数说明--gtest_color=(yes|no|auto)输出命令行时是否使用一些五颜六色的颜色。默认是auto。--gtest_print_time输出命令行时是否打印每个测试案例的执行时间。默认是不打印的。--gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH]

将测试结果输出到一个xml中。

1.--gtest_output=xml:    不指定输出路径时,默认为案例当前路径。

2.--gtest_output=xml:d:\ 指定输出到某个目录

3.--gtest_output=xml:d:\foo.xml 指定输出到d:\foo.xml

如果不是指定了特定的文件路径,gtest每次输出的报告不会覆盖,而会以数字后缀的方式创建。xml的输出内容后面介绍吧。

对案例的异常处理

命令行参数说明--gtest_break_on_failure调试模式下,当案例失败时停止,方便调试--gtest_throw_on_failure当案例失败时以C++异常的方式抛出--gtest_catch_exceptions

是否捕捉异常。gtest默认是不捕捉异常的,因此假如你的测试案例抛了一个异常,很可能会弹出一个对话框,这非常的不友好,同时也阻碍了测试案例的运行。如果想不弹这个框,可以通过设置这个参数来实现。如将--gtest_catch_exceptions设置为一个非零的数。

注意:这个参数只在Windows下有效。

XML报告输出格式

<?xml version="1.0" encoding="UTF-8"?> <testsuites tests="3" failures="1" errors="0" time="35" name="AllTests"> <testsuite name="MathTest" tests="2" failures="1"* errors="0" time="15"> <testcase name="Addition" status="run" time="7" classname=""> <failure message="Value of: add(1, 1) Actual: 3 Expected: 2" type=""/> <failure message="Value of: add(1, -1) Actual: 1 Expected: 0" type=""/> </testcase> <testcase name="Subtraction" status="run" time="5" classname=""> </testcase> </testsuite> <testsuite name="LogicTest" tests="1" failures="0" errors="0" time="5"> <testcase name="NonContradiction" status="run" time="5" classname=""> </testcase> </testsuite> </testsuites>

从报告里可以看出,我们之前在TEST等宏中定义的测试案例名称(testcase_name)在xml测试报告中其实是一个testsuite name,而宏中的测试名称(test_name)在xml测试报告中是一个testcase name,概念上似乎有点混淆,就看你怎么看吧。

当检查点通过时,不会输出任何检查点的信息。当检查点失败时,会有详细的失败信息输出来failure节点。

在我使用过程中发现一个问题,当我同时设置了--gtest_filter参数时,输出的xml报告中还是会包含所有测试案例的信息,只不过那些不被执行的测试案例的status值为“notrun”。而我之前认为的输出的xml报告应该只包含我需要运行的测试案例的信息。不知是否可提供一个只输出需要执行的测试案例的xml报告。因为当我需要在1000个案例中执行其中1个案例时,在报告中很难找到我运行的那个案例,虽然可以查找,但还是很麻烦。

 

 

 

 

最新回复(0)