【解鎖】Catch2——C++測(cè)試框架(Quick Start)

Catch2

Catch2是及其簡(jiǎn)單的C++測(cè)試框架擎淤,與gtest,boost.test和CppUnit相比Catch2非常小,甚至你只需要一個(gè)頭文件就可以輕松的使用了。在小型項(xiàng)目里面可以很方便的用它搭建測(cè)試框架捧杉,同時(shí)配合一個(gè)更為簡(jiǎn)單的打樁框架stub陕见,分分鐘讓你的測(cè)試用例跑起來(lái)。
今天味抖,我們就來(lái)【解鎖】Catch2评甜。

獲取

有兩種方法獲取Catch2:
一種是直接下載頭文件catch.hpp——推薦使用這種方式,可以簡(jiǎn)單的融入你的項(xiàng)目仔涩。
另一種是忍坷,獲取catch2源碼,https://github.com/catchorg/Catch2.git 適合二次開(kāi)發(fā)或者學(xué)習(xí)里面的demo熔脂。

編譯

因?yàn)槲覀兘裉煲ㄟ^(guò)分析幾個(gè)Catch2的examples來(lái)解鎖Catch2的用法佩研,所以用源碼進(jìn)行編譯。

  1. 獲取源碼
git clone https://github.com/catchorg/Catch2.git
  1. 開(kāi)啟examples編譯
(base) frank@deepin:~/git/Catch2$ mkdir build
(base) frank@deepin:~/git/Catch2$ cd build/
(base) frank@deepin:~/git/Catch2/build$ cmake -DCATCH_BUILD_EXAMPLES=ON ../
-- The CXX compiler identification is GNU 9.2.0
-- Check for working CXX compiler: /usr/local/bin/c++
-- Check for working CXX compiler: /usr/local/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PythonInterp: /home/frank/miniconda3/bin/python (found version "3.7.4") 
-- Examples included
-- Configuring done
-- Generating done
-- Build files have been written to: /home/frank/git/Catch2/build
(base) frank@deepin:~/git/Catch2/build$ make -j4

測(cè)試

先從一個(gè)最簡(jiǎn)單的例子開(kāi)始锤悄。

#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>

int Factorial( int number ) {
   return number <= 1 ? number : Factorial( number - 1 ) * number;  // fail
// return number <= 1 ? 1      : Factorial( number - 1 ) * number;  // pass
}

TEST_CASE( "Factorial of 0 is 1 (fail)", "[single-file]" ) {
    REQUIRE( Factorial(0) == 1 );
}

TEST_CASE( "Factorials of 1 and higher are computed (pass)", "[single-file]" ) {
    REQUIRE( Factorial(1) == 1 );
    REQUIRE( Factorial(2) == 2 );
    REQUIRE( Factorial(3) == 6 );
    REQUIRE( Factorial(10) == 3628800 );
}

第1行:#define CATCH_CONFIG_MAIN 韧骗,這個(gè)宏定義了catch的main函數(shù)。

// Standard C/C++ main entry point
int main (int argc, char * argv[]) {
    return Catch::Session().run( argc, argv );
}

第3行:引入catch2零聚,頭文件,這里用的是"<...>"些侍,也就是使用編譯安裝的catch2隶症,make后執(zhí)行make install.咋裝在系統(tǒng)目錄。如果用單個(gè)頭文件則應(yīng)該使用"catch2.hpp"岗宣,確認(rèn)catch2.hpp在你的攻寵目錄活引入了其所在的頭文件目錄蚂会。

第5行:int Factorial( int number ) 是被測(cè)函數(shù)。

第10耗式、14行:分別是兩個(gè)測(cè)試用例
REQUIRE:是斷言胁住。

運(yùn)行結(jié)果如下:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
010-TestCase is a Catch v2.11.1 host application.
Run with -? for options

-------------------------------------------------------------------------------
Factorial of 0 is 1 (fail)
-------------------------------------------------------------------------------
/home/frank/git/Catch2/examples/010-TestCase.cpp:13
...............................................................................

/home/frank/git/Catch2/examples/010-TestCase.cpp:14: FAILED:
  REQUIRE( Factorial(0) == 1 )
with expansion:
  0 == 1

===============================================================================
test cases: 2 | 1 passed | 1 failed
assertions: 5 | 4 passed | 1 failed

自己寫(xiě)main()

如果不想使用Catch2提供的main()函數(shù),往往很多項(xiàng)目需要自己寫(xiě)main()函數(shù)刊咳,那么可以使用下面的方法彪见。

#define CATCH_CONFIG_RUNNER
#include "catch.hpp"

int main( int argc, char* argv[] ) {
  // global setup...

  int result = Catch::Session().run( argc, argv );

  // global clean-up...

  return result;
}

如果想用自己的命令行參數(shù),可以這樣實(shí)現(xiàn):

#define CATCH_CONFIG_RUNNER
#include "catch.hpp"

int main( int argc, char* argv[] )
{
  Catch::Session session; // There must be exactly one instance
  
  int height = 0; // Some user variable you want to be able to set
  
  // Build a new parser on top of Catch's
  using namespace Catch::clara;
  auto cli 
    = session.cli() // Get Catch's composite command line parser
    | Opt( height, "height" ) // bind variable to a new option, with a hint string
        ["-g"]["--height"]    // the option names it will respond to
        ("how high?");        // description string for the help output
        
  // Now pass the new composite back to Catch so it uses that
  session.cli( cli ); 
  
  // Let Catch (using Clara) parse the command line
  int returnCode = session.applyCommandLine( argc, argv );
  if( returnCode != 0 ) // Indicates a command line error
      return returnCode;

  // if set on the command line then 'height' is now set at this point
  if( height > 0 )
      std::cout << "height: " << height << std::endl;

  return session.run();
}

SECTION

你在測(cè)試某個(gè)類的時(shí)候需要對(duì)這個(gè)類整體屬性進(jìn)行設(shè)置娱挨,可以采用setup()活teardow()的方式余指。每個(gè)方法都基于這些特定的屬性,但往往每個(gè)成員方法有需要有不同的測(cè)試場(chǎng)景跷坝,這時(shí)SECTION就可以派上用場(chǎng)酵镜。
也就是說(shuō),這個(gè)類某一組屬性的用例可以是TEST_CASE的范疇柴钻,在這個(gè)TEST_CASE范疇內(nèi)成員方法的不同場(chǎng)景可以使SECTION范疇淮韭。
用下面的例子來(lái)說(shuō)明:

#include <catch2/catch.hpp>

TEST_CASE( "vectors can be sized and resized", "[vector]" ) {

    // For each section, vector v is anew:

    std::vector<int> v( 5 );

    REQUIRE( v.size() == 5 );
    REQUIRE( v.capacity() >= 5 );

    SECTION( "resizing bigger changes size and capacity" ) {
        v.resize( 10 );

        REQUIRE( v.size() == 10 );
        REQUIRE( v.capacity() >= 10 );
    }
    SECTION( "resizing smaller changes size but not capacity" ) {
        v.resize( 0 );

        REQUIRE( v.size() == 0 );
        REQUIRE( v.capacity() >= 5 );
    }
    SECTION( "reserving bigger changes capacity but not size" ) {
        v.reserve( 10 );

        REQUIRE( v.size() == 5 );
        REQUIRE( v.capacity() >= 10 );
    }
    SECTION( "reserving smaller does not change size or capacity" ) {
        v.reserve( 0 );

        REQUIRE( v.size() == 5 );
        REQUIRE( v.capacity() >= 5 );
    }
}

第7行:std::vector<int> v( 5 );是類(TEST_CASE)的范疇。
第13,19,25,31行:是resize()方法不同場(chǎng)景的測(cè)試贴届,是方法(SECTION)范疇靠粪。

這時(shí)你可以用命令行參數(shù)來(lái)指定某一個(gè)SECTION執(zhí)行蜡吧。

(base) frank@deepin:~/git/Catch2/build/examples$ ./100-Fix-Section -c "resizing bigger changes size and capacity" 
===============================================================================
All tests passed (4 assertions in 1 test case)

BDD風(fēng)格

總體上和SECTION類似,只不過(guò)更接近自然語(yǔ)言或行為庇配,BDD(行為驅(qū)動(dòng)開(kāi)發(fā))——你可以把測(cè)試用例當(dāng)做你的需求文檔斩跌。
例子:

#include <catch2/catch.hpp>

SCENARIO( "vectors can be sized and resized", "[vector]" ) {

    GIVEN( "A vector with some items" ) {
        std::vector<int> v( 5 );

        REQUIRE( v.size() == 5 );
        REQUIRE( v.capacity() >= 5 );

        WHEN( "the size is increased" ) {
            v.resize( 10 );

            THEN( "the size and capacity change" ) {
                REQUIRE( v.size() == 10 );
                REQUIRE( v.capacity() >= 10 );
            }
        }
        WHEN( "the size is reduced" ) {
            v.resize( 0 );

            THEN( "the size changes but not capacity" ) {
                REQUIRE( v.size() == 0 );
                REQUIRE( v.capacity() >= 5 );
            }
        }
        WHEN( "more capacity is reserved" ) {
            v.reserve( 10 );

            THEN( "the capacity changes but not the size" ) {
                REQUIRE( v.size() == 5 );
                REQUIRE( v.capacity() >= 10 );
            }
        }
        WHEN( "less capacity is reserved" ) {
            v.reserve( 0 );

            THEN( "neither size nor capacity are changed" ) {
                REQUIRE( v.size() == 5 );
                REQUIRE( v.capacity() >= 5 );
            }
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市捞慌,隨后出現(xiàn)的幾起案子耀鸦,更是在濱河造成了極大的恐慌,老刑警劉巖啸澡,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袖订,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嗅虏,警方通過(guò)查閱死者的電腦和手機(jī)洛姑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)皮服,“玉大人楞艾,你說(shuō)我怎么就攤上這事×涔悖” “怎么了硫眯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)择同。 經(jīng)常有香客問(wèn)我两入,道長(zhǎng),這世上最難降的妖魔是什么敲才? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任裹纳,我火速辦了婚禮,結(jié)果婚禮上紧武,老公的妹妹穿的比我還像新娘剃氧。我一直安慰自己,他們只是感情好脏里,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布她我。 她就那樣靜靜地躺著,像睡著了一般迫横。 火紅的嫁衣襯著肌膚如雪番舆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天矾踱,我揣著相機(jī)與錄音恨狈,去河邊找鬼。 笑死呛讲,一個(gè)胖子當(dāng)著我的面吹牛禾怠,可吹牛的內(nèi)容都是我干的返奉。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吗氏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼芽偏!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起弦讽,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤污尉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后往产,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體被碗,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年仿村,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锐朴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蔼囊,死狀恐怖焚志,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畏鼓,我是刑警寧澤娩嚼,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站滴肿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏佃迄。R本人自食惡果不足惜泼差,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望呵俏。 院中可真熱鬧堆缘,春花似錦、人聲如沸普碎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)麻车。三九已至缀皱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間动猬,已是汗流浹背啤斗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赁咙,地道東北人钮莲。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓免钻,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親崔拥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子极舔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容