PHPUnit 加速技巧分享

file

具備高效的測(cè)試一如編寫(xiě)高效的應(yīng)用一樣重要图甜。作為開(kāi)發(fā)者來(lái)說(shuō),迅速得知你剛編寫(xiě)的代碼是否能夠正常運(yùn)行,能夠讓開(kāi)發(fā)效率大大提升规阀。接下來(lái)我們將會(huì)介紹一些可以快速實(shí)現(xiàn)的小技巧,讓你的代碼測(cè)試變得更快瘦麸。

該示例測(cè)試套件有意地模擬更廣泛的測(cè)試集合谁撼,并突出改進(jìn)的可行性。真實(shí)情況下,效率的提升可能有所差異厉碟。

ParaTest

這個(gè)包 是一個(gè)用來(lái)運(yùn)行你的測(cè)試套件的 PHPUnit 擴(kuò)展喊巍。 和 PHPUnit 不一樣的是它可以利用你的多核 CPU 來(lái)并行的運(yùn)行測(cè)試用例。

你可以通過(guò) composer 來(lái)將它作為一個(gè)開(kāi)發(fā)依賴(lài)安裝以后開(kāi)始使用 ParaTest 箍鼓。

composer require --dev brianium/paratest

現(xiàn)在我們就可以像調(diào)用 PHPUnit 一樣來(lái)調(diào)用 ParaTest 了崭参。它會(huì)自動(dòng)的根據(jù)你機(jī)器 CPU 核心數(shù)來(lái)判斷要啟動(dòng)多少個(gè)進(jìn)程。

<img src="https://user-gold-cdn.xitu.io/2019/1/21/1686e1efd40e5bd7?w=1440&h=611&f=png&s=233798" class="rm-style">

上面款咖,你可以看到在控制臺(tái)中輸出了運(yùn)行測(cè)試用例啟動(dòng)了5個(gè)并行的進(jìn)程何暮。對(duì)比一下,下面用 PHPUnit 運(yùn)行了同樣的測(cè)試用例铐殃。

<img src="https://user-gold-cdn.xitu.io/2019/1/21/1686e1efd2d2a874?w=525&h=177&f=png&s=20131" class="rm-style">

1.49 秒 和 6.15秒 !

盡管 ParaTest 可以自己確定進(jìn)程數(shù)海洼,你也可以嘗試設(shè)置進(jìn)程數(shù)針對(duì)你的機(jī)器進(jìn)行優(yōu)化。使用 ---processes 選項(xiàng)富腊,你可以增加或減少進(jìn)程數(shù)坏逢,因?yàn)椴⒉皇沁M(jìn)程數(shù)越多測(cè)試效果越好。

./vendor/bin/paratest --processes 6

警告: 使用 ParaTest 測(cè)試數(shù)據(jù)庫(kù)前赘被,需要考慮如何準(zhǔn)備數(shù)據(jù)是整。如果使用 Lavarel 的 RefreshDatabase ,運(yùn)行測(cè)試用例后會(huì)回滾或者遷移數(shù)據(jù)庫(kù)來(lái)寫(xiě)入 民假。 相反的是浮入,通過(guò) DatabaseTransactions 跳過(guò)數(shù)據(jù)持久化, 這在運(yùn)行測(cè)試期間不會(huì)嘗試修改數(shù)據(jù)羊异。

重試失敗的測(cè)試

PHPUnit 有個(gè)非常方便的功能就是舵盈,允許你重新只運(yùn)行上次測(cè)試中失敗的測(cè)試.。如果你正在進(jìn)行紅綠復(fù)建風(fēng)格的 TDD 開(kāi)發(fā)球化,它將會(huì)加快你的開(kāi)發(fā)周期秽晚。讓我們從一個(gè)通過(guò)所有現(xiàn)存測(cè)試的測(cè)試套件來(lái)了解一下它這個(gè)功能。

<img src="https://user-gold-cdn.xitu.io/2019/1/21/1686e1efface2e99?w=525&h=162&f=png&s=13166" class="rm-style">

接下來(lái)筒愚,新增一個(gè) red-green-refactor 測(cè)試模型的測(cè)試用例赴蝇,預(yù)期失敗:

<img src="https://user-gold-cdn.xitu.io/2019/1/21/1686e1effad4dc01?w=525&h=151&f=png&s=12965" class="rm-style">

在更改代碼庫(kù)之后你認(rèn)為新測(cè)試會(huì)通過(guò)巢掺,你想重新運(yùn)行該測(cè)試套件以期能按預(yù)期運(yùn)行句伶。問(wèn)題在于這個(gè)套件現(xiàn)在已經(jīng)要花 1.3 秒的時(shí)間才能運(yùn)行,隨著測(cè)試代碼量的增加陆淀,所需嚴(yán)重等待的時(shí)間也隨之增加考余。

如果我們只能運(yùn)行失敗的測(cè)試,那不是很好轧苫? 非常幸運(yùn)的是 PHPUnit v7.3添加了這樣做的能力楚堤。

<img src="https://user-gold-cdn.xitu.io/2019/1/21/1686e1effaec15cb?w=525&h=151&f=png&s=11977" class="rm-style">

為了實(shí)現(xiàn)這個(gè)功能,請(qǐng)將 cacheResult =“true” 添加到 phpunit.xml配置中。 PHPUnit 會(huì)始終記住以前哪些測(cè)試失敗了身冬。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit cacheResult="true"
         backupGlobals="false"
         ...>

現(xiàn)在衅胀,當(dāng)我們運(yùn)行我們的測(cè)試單元時(shí), PHPUnit 將記住哪些測(cè)試失敗并使用以下選項(xiàng)讓我們可以重新運(yùn)行那些失敗的測(cè)試單元酥筝。

./vendor/bin/phpunit --order-by=defects --stop-on-defect

我們不再需要等待整個(gè)測(cè)試單元運(yùn)行滚躯,以查看我們?cè)噲D解決的一個(gè)測(cè)試是否正在通過(guò)。

將緩存文件 .phpunit.result.cache 添加到 .gitignore 也是一個(gè)好主意嘿歌,這樣它就不會(huì)最終被提交到你的倉(cāng)庫(kù)里掸掏。

慢測(cè)試分組

PHPUnit 允許你用 @group 注解來(lái)將測(cè)試用例添加到不同的「分組」。如果你有一些測(cè)試用例尤其的慢的話(huà)宙帝,最好是將他們分到同一個(gè)組丧凤。

class MyTest extends TestCase
{
    public function test_that_is_fast()
    {
        $this->assertTrue(true);
    }

    /**
     * @group slow
     */
    public function test_that_is_slow()
    {
        sleep(10);

        $this->assertTrue(true);
    }

    /**
     * @group slow
     */
    public function test_that_is_slow_2_adrians_revenge()
    {
        sleep(10);

        $this->assertFalse(false);
    }
}

在這個(gè)例子中,我們有兩個(gè)測(cè)試用例要運(yùn)行10秒鐘茄唐。 在我們開(kāi)發(fā)周期內(nèi)最后一件要做的事情就是運(yùn)行測(cè)試用例,尤其是在做測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的時(shí)候需要測(cè)試用例瞬時(shí)執(zhí)行完成蝇更。

由于兩個(gè)慢的測(cè)試用例都在同一個(gè)分組所以你可以通過(guò) PHPUnit 的 --exclude-group 選項(xiàng)在某一次測(cè)試運(yùn)行中來(lái)排除他們沪编。

./vendor/bin/phpunit --exclude-group slow

這個(gè)命令將會(huì)運(yùn)行你測(cè)試用例中除了 slow 分組的所有測(cè)試用例。 測(cè)試用例分組還有一個(gè)好處年扩,比如說(shuō)你需要將你所有的慢測(cè)試用例整理成文檔以便后面再來(lái)優(yōu)化他們蚁廓。

然而在部署到生產(chǎn)環(huán)境前進(jìn)行一些檢查確保所有測(cè)試用例能通過(guò),包括慢的測(cè)試用例厨幻。 設(shè)置一個(gè) CI 管道來(lái)運(yùn)行測(cè)試用例會(huì)是個(gè)不錯(cuò)的方法相嵌。

過(guò)濾測(cè)試

PHPUnit 有一個(gè) --filter 選項(xiàng),它接受一個(gè)模式來(lái)確定運(yùn)行哪些測(cè)試况脆。例如饭宾,如果您將所有測(cè)試配置命名空間 ,則可以通過(guò)指定命名空間來(lái)運(yùn)行特定的測(cè)試子集格了。 以下命令僅在 Tests\Unit\Models 命名空間中運(yùn)行測(cè)試并排除所有其他命令看铆。

./vendor/bin/phpunit --filter 'Tests\\Unit\\Models'

--filter 選項(xiàng)是靈活的,允許通過(guò) methodName盛末,Class::methodName 進(jìn)行過(guò)濾弹惦,甚至可以通過(guò)帶有 /path/to/my/test.php 的文件路徑進(jìn)行過(guò)濾。您應(yīng)該查看此選項(xiàng)的 PHPUnit docs 并查看更多的內(nèi)容悄但。

密碼哈希次數(shù)

Laravel 默認(rèn)使用 bcrypt 密碼哈希算法棠隐,這種設(shè)計(jì)在系統(tǒng)資源上緩慢且昂貴。如果您的測(cè)試是驗(yàn)證用戶(hù)密碼檐嚣,可以通過(guò)設(shè)置算法使用的次數(shù)來(lái)減少測(cè)試運(yùn)行的時(shí)間助泽,因?yàn)樗鼒?zhí)行的次數(shù)越多,所需的時(shí)間就越長(zhǎng)。

如果你的應(yīng)用程序與 laravel/laravelproject 中的最新更改保持同步报咳,你會(huì)發(fā)現(xiàn)哈希次數(shù)的數(shù)量可以使用環(huán)境變量進(jìn)行自定義侠讯。bcrypt 允許的最小次數(shù)已經(jīng)設(shè)置為4,在 phpunit.xml file.

但是暑刃,如果您沒(méi)有同步最新的更新厢漩,可以使用 Hash 門(mén)面在CreatesApplication trait 中設(shè)置它。

public function createApplication()
{
    $app = require __DIR__.'/../bootstrap/app.php';

    $app->make(Kernel::class)->bootstrap();

    // 設(shè)置 bcrypt 哈希次數(shù)...
    Hash::rounds(4);

    return $app;
}

內(nèi)存數(shù)據(jù)庫(kù)

利用內(nèi)存數(shù)據(jù)庫(kù) SQLite 岩臣,是另一種加速測(cè)試的方式溜嗜。 你可以通過(guò)在 phpunit.xml 配置文件里添加兩個(gè)環(huán)境字段,來(lái)迅速開(kāi)啟它架谎。

<php>
    ...
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
</php>

說(shuō)明:盡管這樣看上去很容易炸宵,你應(yīng)該考慮生產(chǎn)環(huán)境數(shù)據(jù)庫(kù)一致性問(wèn)題。如果你在生產(chǎn)環(huán)境使用了 MySQL 數(shù)據(jù)庫(kù)谷扣,你應(yīng)該警惕引入不同數(shù)據(jù)庫(kù)所帶來(lái)的測(cè)試上的不同土全,比如 SQLite。我在這篇文章 my feature test suite setup 里描述了很多細(xì)節(jié)上的不同點(diǎn)会涎。我認(rèn)為相比通過(guò)提升一點(diǎn)速度帶來(lái)的好處裹匙,保持生產(chǎn)環(huán)境一致更重要。

禁用 Xdebug

如果你平時(shí)用不到 Xdebug 的話(huà)末秃,可以禁用掉它概页,因?yàn)樗鼤?huì)降低 PHP 執(zhí)行速度,導(dǎo)致測(cè)試用例運(yùn)行緩慢练慕。如果你日常使用它來(lái)調(diào)試的話(huà)惰匙,為了執(zhí)行測(cè)試而禁用它可能不是一個(gè)好的選擇 —— 但你始終要知道這一點(diǎn)當(dāng)你關(guān)注測(cè)試用例執(zhí)行速度時(shí)。

你可以在下面這個(gè)測(cè)試用例看到铃将,一旦我們禁用了 Xdebug项鬼,執(zhí)行速度將會(huì)有極大的提高。下面是這個(gè)測(cè)試用例在 Xdebug 啟用時(shí)的執(zhí)行情況:

<img src="https://user-gold-cdn.xitu.io/2019/1/21/1686e1f022f017f1?w=525&h=151&f=png&s=11703" class="rm-style">

以及同樣的測(cè)試用例在 Xdebug 禁用時(shí)的執(zhí)行情況:

<img src="https://user-gold-cdn.xitu.io/2019/1/21/1686e1f023050434?w=525&h=151&f=png&s=11374" class="rm-style">

修復(fù)測(cè)試速度過(guò)慢

當(dāng)然我們最希望看到的段落是是:修復(fù)測(cè)試速度過(guò)慢劲阎!如果您正在努力確定哪些測(cè)試導(dǎo)致測(cè)試單元變慢時(shí)秃臣,您可能需要查看 PHPUnit Report 。它是一個(gè)開(kāi)源工具哪工,允許您通過(guò)生成如下所示的云可視化您的測(cè)試單元的性能奥此,其中較大的氣泡代表慢速測(cè)試。這將使您能夠在單元中找到最慢的測(cè)試并逐步提高其性能雁比。

file

轉(zhuǎn)自 PHP / Laravel 開(kāi)發(fā)者社區(qū) https://laravel-china.org/topics/22341

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末稚虎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子偎捎,更是在濱河造成了極大的恐慌蠢终,老刑警劉巖序攘,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異寻拂,居然都是意外死亡程奠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)祭钉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瞄沙,“玉大人,你說(shuō)我怎么就攤上這事慌核【嗑常” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵垮卓,是天一觀的道長(zhǎng)垫桂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)粟按,這世上最難降的妖魔是什么诬滩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮灭将,結(jié)果婚禮上疼鸟,老公的妹妹穿的比我還像新娘。我一直安慰自己宗侦,他們只是感情好愚臀,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布忆蚀。 她就那樣靜靜地躺著矾利,像睡著了一般。 火紅的嫁衣襯著肌膚如雪馋袜。 梳的紋絲不亂的頭發(fā)上男旗,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音欣鳖,去河邊找鬼察皇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泽台,可吹牛的內(nèi)容都是我干的什荣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼怀酷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稻爬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蜕依,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桅锄,失蹤者是張志新(化名)和其女友劉穎琉雳,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體友瘤,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翠肘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辫秧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片束倍。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖茶没,靈堂內(nèi)的尸體忽然破棺而出肌幽,到底是詐尸還是另有隱情,我是刑警寧澤抓半,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布喂急,位于F島的核電站,受9級(jí)特大地震影響笛求,放射性物質(zhì)發(fā)生泄漏廊移。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一探入、第九天 我趴在偏房一處隱蔽的房頂上張望狡孔。 院中可真熱鬧,春花似錦蜂嗽、人聲如沸苗膝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辱揭。三九已至,卻和暖如春病附,著一層夾襖步出監(jiān)牢的瞬間问窃,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工完沪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留域庇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓覆积,卻偏偏與公主長(zhǎng)得像听皿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宽档,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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