? gtest的問(wèn)題
gtest需要安裝有時(shí)候帶來(lái)很多不方便,比如需要經(jīng)常切換gcc和clang的時(shí)候就比較麻煩,安裝的gtest可能在另一個(gè)編譯器下編譯不過(guò), 編寫(xiě)跨平臺(tái)程序的時(shí)候需要多次安裝gtest,非常不便。另外一個(gè)問(wèn)題是網(wǎng)絡(luò)原因,下載安裝gtest或者git上拉gtest都可能因?yàn)榫W(wǎng)絡(luò)原因失敗。
現(xiàn)代C++ unit test庫(kù)
除了gtest之外,還有很多輕量級(jí)易用的單元測(cè)試庫(kù),比如doctest和catch,相比gtest需要編譯/安裝,他們都是header only的,直接包含到工程里就可以做單元測(cè)試了,portable又沒(méi)有任何依賴(lài),而且對(duì)編譯器版本要求也不高,只需要C++11就行了,用了之后只有一個(gè)字:爽!
這里推薦使用doctest(https://github.com/doctest/doctest),原因是它的性能比catch更好(https://github.com/doctest/doctest/blob/master/doc/markdown/benchmarks.md),當(dāng)然也比gtest好, 來(lái)看看doctest怎么用的吧。
doctest基本用法
?
#define?DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include?"doctest.h" TEST_CASE("vectors?can?be?sized?and?resized")?{ ????std::vector?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是類(lèi)似的,我覺(jué)得doctest更酷更實(shí)用的一個(gè)特性是SUBCASE, 允許在當(dāng)前case下增加更多的子case去測(cè)試一些special一些的東西,非常實(shí)用,這也是相比gtest更好的一個(gè)地方。
doctest提供了很多豐富的宏,完全可以滿(mǎn)足我們的測(cè)試需要。
doctest的斷言宏
CHECK宏是只檢查并不會(huì)終止測(cè)試,REQUIRE宏則會(huì)終止測(cè)試和gtest里面的ASSET_XX宏類(lèi)似,這兩個(gè)宏也是平時(shí)做單測(cè)時(shí)用得最多的兩個(gè)宏了。除此之外,還有更豐富的宏。比如:
?
?is?one?of?3?possible:?REQUIRE/CHECK/WARN. _EQ(left,?right)?-?same?as? (left?==?right) _NE(left,?right)?-?same?as? (left?!=?right) _GT(left,?right)?-?same?as? (left?>?right) _LT(left,?right)?-?same?as? (left?_GE(left,?right)?-?same?as? (left?>=?right) _LE(left,?right)?-?same?as? (left?<=?right) _UNARY(expr)?-?same?as? (expr) _UNARY_FALSE(expr)?-?same?as? _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);_NOTHROW(expression)
?
doctest異常的宏非常有特色,比gtest的異常斷言更強(qiáng)大,可以同時(shí)比較異常類(lèi)型和異常信息。
也許有人會(huì)說(shuō)gtest除了這些基本的測(cè)試斷言之外還有g(shù)mock呀,doctest沒(méi)有g(shù)mock這樣的mock庫(kù)。是的,doctest確實(shí)沒(méi)有mock庫(kù),但是doctest很容易和其它現(xiàn)代C++的mock庫(kù)結(jié)合起來(lái)使用,比如FakeIt。
現(xiàn)代C++ mock庫(kù)
FakeIt(https://github.com/eranpeer/FakeIt)是C++11寫(xiě)的header only的mock庫(kù),用起來(lái)也很方便:
?
struct?SomeInterface?{ ????virtual?int?foo(int)?=?0; ????virtual?int?bar(string)?=?0; }; Mock?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兩個(gè)header only的庫(kù)就可以完美替代gtest了。那么還有一個(gè)就是benchmark了,google有一個(gè)benchmark庫(kù)也是需要編譯/安裝的,有沒(méi)有什么現(xiàn)代C++的benchmark庫(kù)來(lái)替代google 的benchmark庫(kù)呢?當(dāng)然有,比如nanobench。
現(xiàn)代C++ benchmark庫(kù)
nanobench(https://github.com/martinus/nanobench)也是C++11寫(xiě)的header only的庫(kù),使用起來(lái)也很簡(jiǎn)單,包含頭文件即可。
?
#define?ANKERL_NANOBENCH_IMPLEMENT #include?int?main()?{ ????double?d?=?1.0; ????ankerl::Bench().run("some?double?ops",?[&]?{ ????????d?+=?1.0?/?d; ????????if?(d?>?5.0)?{ ????????????d?-=?5.0; ????????} ????????ankerl::doNotOptimizeAway(d); ????}); }
?
測(cè)試結(jié)果:
?
|???????????????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`
?
總結(jié)
用現(xiàn)代C++測(cè)試工具鏈:doctest+FakeIt+nanobench, 可以完美地替代gtest/gmock和google bench,沒(méi)有任何依賴(lài),無(wú)需安裝,直接包含頭文件就可以用,非常容易集成和使用,是時(shí)候拋棄google test和google bench了!
評(píng)論