玩转Google开源C++单元测试框架Google Test系列(gtest)之五 - 死亡测试
一、前言
“死亡測試”名字比較恐怖,這里的“死亡”指的的是程序的崩潰。通常在測試過程中,我們需要考慮各種各樣的輸入,有的輸入可能直接導致程序崩潰,這時我們就需要檢查程序是否按照預期的方式掛掉,這也就是所謂的“死亡測試”。gtest的死亡測試能做到在一個安全的環境下執行崩潰的測試案例,同時又對崩潰結果進行驗證。
二、使用的宏
| Fatal assertion | Nonfatal assertion | Verifies |
| ASSERT_DEATH(statement, regex`); | EXPECT_DEATH(statement, regex`); | statement?crashes with the given error |
| ASSERT_EXIT(statement, predicate, regex`); | EXPECT_EXIT(statement, predicate, regex`); | statement?exits with the given error and its exit code matches?predicate |
?
由于有些異常只在Debug下拋出,因此還提供了*_DEBUG_DEATH,用來處理Debug和Realease下的不同。
三、*_DEATH(statement, regex`)
1. statement是被測試的代碼語句
2. regex是一個正則表達式,用來匹配異常時在stderr中輸出的內容
如下面的例子:?
{
????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:
如果程序正常退出并且退出碼與exit_code相同則返回?true
?
如果程序被signal_number信號kill的話就返回true
3. regex是一個正則表達式,用來匹配異常時在stderr中輸出的內容
這里, 要說明的是,*_DEATH其實是對*_EXIT進行的一次包裝,*_DEATH的predicate判斷進程是否以非0退出碼退出或被一個信號殺死。
例子:
{
????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
}
?
六、關于正則表達式
在POSIX系統(Linux, Cygwin, 和 Mac)中,gtest的死亡測試中使用的是POSIX風格的正則表達式,想了解POSIX風格表達式可參考:?
1.?POSIX extended regular expression
2.?Wikipedia entry.
在Windows系統中,gtest的死亡測試中使用的是gtest自己實現的簡單的正則表達式語法。 相比POSIX風格,gtest的簡單正則表達式少了很多內容,比如?("x|y"), ("(xy)"), ("[xy]") 和("x{5,7}")都不支持。
下面是簡單正則表達式支持的一些內容:
| | matches any literal character?c |
| \\d | matches any decimal digit |
| \\D | matches any character that's not a decimal digit |
| \\f | matches?\f |
| \\n | matches?\n |
| \\r | matches?\r |
| \\s | matches any ASCII whitespace, including?\n |
| \\S | matches any character that's not a whitespace |
| \\t | matches?\t |
| \\v | matches?\v |
| \\w | matches any letter,?_, or decimal digit |
| \\W | matches any character that?\\w?doesn't match |
| \\c | matches any literal character?c, which must be a punctuation |
| . | matches any single character except?\n |
| A? | matches 0 or 1 occurrences of?A |
| A* | matches 0 or many occurrences of?A |
| A+ | matches 1 or many occurrences of?A |
| ^ | matches the beginning of a string (not that of each line) |
| $ | matches the end of a string (not that of each line) |
| xy | matches?x?followed by?y |
?
gtest定義兩個宏,用來表示當前系統支持哪套正則表達式風格:
1. POSIX風格:GTEST_USES_POSIX_RE?= 1?
2. Simple風格:GTEST_USES_SIMPLE_RE=1
七、死亡測試運行方式
1. fast方式(默認的方式)
testing::FLAGS_gtest_death_test_style?=?"fast"; 2. 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`),我們可以非常方便的編寫導致崩潰的測試案例,并且在不影響其他案例執行的情況下,對崩潰案例的結果進行檢查。
總結
以上是生活随笔為你收集整理的玩转Google开源C++单元测试框架Google Test系列(gtest)之五 - 死亡测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 玩转Google开源C++单元测试框架G
- 下一篇: 玩转Google开源C++单元测试框架G