gtest的問題
gtest需要安裝有時候帶來很多不方便,比如需要經常切換gcc和clang的時候就比較麻煩,安裝的gtest可能在另一個編譯器下編譯不過, 編寫跨平臺程序的時候需要多次安裝gtest,非常不便。另外一個問題是網絡原因,下載安裝gtest或者git上拉gtest都可能因為網絡原因失敗。
現代C++ unit test庫
除了gtest之外,還有很多輕量級易用的單元測試庫,比如doctest和catch,相比gtest需要編譯/安裝,他們都是header only的,直接包含到工程里就可以做單元測試了,portable又沒有任何依賴,而且對編譯器版本要求也不高,只需要C++11就行了,用了之后只有一個字:爽!
這里推薦使用doctest(https://github.com/doctest/doctest),原因是它的性能比catch更好(https://github.com/doctest/doctest/blob/master/doc/markdown/benchmarks.md),當然也比gtest好, 來看看doctest怎么用的吧。
doctest基本用法
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
TEST_CASE("vectors can be sized and resized") {
std::vector<int> v(5);
REQUIRE(v.size() == 5);
REQUIRE(v.capacity() >= 5);
SUBCASE("adding to the vector increases it's size") {
v.push_back(1);
CHECK(v.size() == 6);
CHECK(v.capacity() >= 6);
}
SUBCASE("reserving increases just the capacity") {
v.reserve(6);
CHECK(v.size() == 5);
CHECK(v.capacity() >= 6);
}
}
這里使用CHECK做斷言和gtest的EXPECT_xx是類似的,我覺得doctest更酷更實用的一個特性是SUBCASE, 允許在當前case下增加更多的子case去測試一些special一些的東西,非常實用,這也是相比gtest更好的一個地方。
doctest提供了很多豐富的宏,完全可以滿足我們的測試需要。
doctest的斷言宏
CHECK宏是只檢查并不會終止測試,REQUIRE宏則會終止測試和gtest里面的ASSET_XX宏類似,這兩個宏也是平時做單測時用得最多的兩個宏了。除此之外,還有更豐富的宏。比如:
<LEVEL> is one of 3 possible: REQUIRE/CHECK/WARN.
<LEVEL>_EQ(left, right) - same as <LEVEL>(left == right)
<LEVEL>_NE(left, right) - same as <LEVEL>(left != right)
<LEVEL>_GT(left, right) - same as <LEVEL>(left > right)
<LEVEL>_LT(left, right) - same as <LEVEL>(left < right)
<LEVEL>_GE(left, right) - same as <LEVEL>(left >= right)
<LEVEL>_LE(left, right) - same as <LEVEL>(left <= right)
<LEVEL>_UNARY(expr) - same as <LEVEL>(expr)
<LEVEL>_UNARY_FALSE(expr) - same as <LEVEL>_FALSE(expr)
判斷異常的宏
CHECK_THROWS_AS(func(), const std::exception&);
CHECK_THROWS_AS(func(), std::exception); // same as above
CHECK_THROWS_WITH(func(), "invalid operation!");
CHECK_THROWS_WITH_AS(func(), "invalid operation!", std::runtime_error);
<LEVEL>_NOTHROW(expression)
doctest異常的宏非常有特色,比gtest的異常斷言更強大,可以同時比較異常類型和異常信息。
也許有人會說gtest除了這些基本的測試斷言之外還有gmock呀,doctest沒有gmock這樣的mock庫。是的,doctest確實沒有mock庫,但是doctest很容易和其它現代C++的mock庫結合起來使用,比如FakeIt。
現代C++ mock庫
FakeIt(https://github.com/eranpeer/FakeIt)是C++11寫的header only的mock庫,用起來也很方便:
struct SomeInterface {
virtual int foo(int) = 0;
virtual int bar(string) = 0;
};
Mock<SomeInterface> mock;
When(Method(mock,foo)).Return(0);
SomeInterface &i = mock.get();
// Production code
i.foo(1);
// Verify method mock.foo was invoked.
Verify(Method(mock,foo));
// Verify method mock.foo was invoked with specific arguments.
Verify(Method(mock,foo).Using(1));
用doctest+FakeIt兩個header only的庫就可以完美替代gtest了。那么還有一個就是benchmark了,google有一個benchmark庫也是需要編譯/安裝的,有沒有什么現代C++的benchmark庫來替代google 的benchmark庫呢?當然有,比如nanobench。
現代C++ benchmark庫
nanobench(https://github.com/martinus/nanobench)也是C++11寫的header only的庫,使用起來也很簡單,包含頭文件即可。
#define ANKERL_NANOBENCH_IMPLEMENT
#include <nanobench.h>
int main() {
double d = 1.0;
ankerl::nanobench::Bench().run("some double ops", [&] {
d += 1.0 / d;
if (d > 5.0) {
d -= 5.0;
}
ankerl::nanobench::doNotOptimizeAway(d);
});
}
測試結果:
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
| 7.52 | 132,948,239.79 | 1.1% | 6.65 | 24.07 | 0.276 | 1.00 | 8.9% | 0.00 | `some double ops`
總結
用現代C++測試工具鏈:doctest+FakeIt+nanobench, 可以完美地替代gtest/gmock和google bench,沒有任何依賴,無需安裝,直接包含頭文件就可以用,非常容易集成和使用,是時候拋棄google test和google bench了!
出自:purecpp
來源:www.purecpp.org