PHPUnit 加速技巧分享

Summer__發表於2019-01-21

file

具備高效的測試一如編寫高效的應用一樣重要。作為開發者來說,迅速得知你剛編寫的程式碼是否能夠正常執行,能夠讓開發效率大大提升。接下來我們將會介紹一些可以快速實現的小技巧,讓你的程式碼測試變得更快。

該示例測試套件有意地模擬更廣泛的測試集合,並突出改進的可行性。真實情況下,效率的提升可能有所差異。

ParaTest

這個包 是一個用來執行你的測試套件的 PHPUnit 擴充套件。 和 PHPUnit 不一樣的是它可以利用你的多核 CPU 來並行的執行測試用例。

你可以通過 composer 來將它作為一個開發依賴安裝以後開始使用 ParaTest

composer require --dev brianium/paratest

複製程式碼

現在我們就可以像呼叫 PHPUnit 一樣來呼叫 ParaTest 了。它會自動的根據你機器 CPU 核心數來判斷要啟動多少個程式。

PHPUnit 加速技巧分享

上面,你可以看到在控制檯中輸出了執行測試用例啟動了5個並行的程式。對比一下,下面用 PHPUnit 執行了同樣的測試用例。

PHPUnit 加速技巧分享

1.49 秒 和 6.15秒 !

儘管 ParaTest 可以自己確定程式數,你也可以嘗試設定程式數針對你的機器進行優化。使用  ---processes 選項,你可以增加或減少程式數,因為並不是程式數越多測試效果越好。

./vendor/bin/paratest --processes 6

複製程式碼

警告: 使用 ParaTest 測試資料庫前,需要考慮如何準備資料。如果使用 Lavarel 的  RefreshDatabase ,執行測試用例後會回滾或者遷移資料庫來寫入 。 相反的是,通過  DatabaseTransactions  跳過資料持久化, 這在執行測試期間不會嘗試修改資料。

重試失敗的測試

PHPUnit 有個非常方便的功能就是,允許你重新只執行上次測試中失敗的測試.。如果你正在進行紅綠復建風格的 TDD 開發,它將會加快你的開發週期。讓我們從一個通過所有現存測試的測試套件來了解一下它這個功能。

PHPUnit 加速技巧分享

接下來,新增一個 red-green-refactor 測試模型的測試用例,預期失敗:

PHPUnit 加速技巧分享

在更改程式碼庫之後你認為新測試會通過,你想重新執行該測試套件以期能按預期執行。問題在於這個套件現在已經要花 1.3 秒的時間才能執行,隨著測試程式碼量的增加,所需嚴重等待的時間也隨之增加。

如果我們只能執行失敗的測試,那不是很好? 非常幸運的是 PHPUnit v7.3新增了這樣做的能力

PHPUnit 加速技巧分享

為了實現這個功能,請將 cacheResult =“true” 新增到 phpunit.xml配置中。 PHPUnit 會始終記住以前哪些測試失敗了。

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

複製程式碼

現在,當我們執行我們的測試單元時, PHPUnit 將記住哪些測試失敗並使用以下選項讓我們可以重新執行那些失敗的測試單元。

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

複製程式碼

我們不再需要等待整個測試單元執行,以檢視我們試圖解決的一個測試是否正在通過。

將快取檔案 .phpunit.result.cache 新增到 .gitignore 也是一個好主意,這樣它就不會最終被提交到你的倉庫裡。

慢測試分組

PHPUnit 允許你用 @group 註解來將測試用例新增到不同的「分組」。如果你有一些測試用例尤其的慢的話,最好是將他們分到同一個組。

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);
    }
}

複製程式碼

在這個例子中,我們有兩個測試用例要執行10秒鐘。 在我們開發週期內最後一件要做的事情就是執行測試用例,尤其是在做測試驅動開發的時候需要測試用例瞬時執行完成。

由於兩個慢的測試用例都在同一個分組所以你可以通過 PHPUnit 的 --exclude-group 選項在某一次測試執行中來排除他們。

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

複製程式碼

這個命令將會執行你測試用例中除了 slow 分組的所有測試用例。 測試用例分組還有一個好處,比如說你需要將你所有的慢測試用例整理成文件以便後面再來優化他們。

然而在部署到生產環境前進行一些檢查確保所有測試用例能通過,包括慢的測試用例。 設定一個 CI 管道來執行測試用例會是個不錯的方法。

過濾測試

PHPUnit 有一個 --filter 選項,它接受一個模式來確定執行哪些測試。例如,如果您將所有測試配置名稱空間 ,則可以通過指定名稱空間來執行特定的測試子集。 以下命令僅在 Tests\Unit\Models 名稱空間中執行測試並排除所有其他命令。

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

複製程式碼

--filter 選項是靈活的,允許通過 methodNameClass::methodName 進行過濾,甚至可以通過帶有 /path/to/my/test.php 的檔案路徑進行過濾。您應該檢視此選項的 PHPUnit docs 並檢視更多的內容。

密碼雜湊次數

Laravel 預設使用 bcrypt 密碼雜湊演算法,這種設計在系統資源上緩慢且昂貴。如果您的測試是驗證使用者密碼,可以通過設定演算法使用的次數來減少測試執行的時間,因為它執行的次數越多,所需的時間就越長。

如果你的應用程式與 laravel/laravelproject 中的最新更改保持同步,你會發現雜湊次數的數量可以使用環境變數進行自定義。bcrypt 允許的最小次數已經設定為4,在 phpunit.xml file.

但是,如果您沒有同步最新的更新,可以使用 Hash 門面在CreatesApplication trait 中設定它。

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

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

    // 設定 bcrypt 雜湊次數...
    Hash::rounds(4);

    return $app;
}

複製程式碼

記憶體資料庫

利用記憶體資料庫 SQLite ,是另一種加速測試的方式。 你可以通過在 phpunit.xml  配置檔案裡新增兩個環境欄位,來迅速開啟它。

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

複製程式碼

說明:儘管這樣看上去很容易,你應該考慮生產環境資料庫一致性問題。如果你在生產環境使用了 MySQL 資料庫,你應該警惕引入不同資料庫所帶來的測試上的不同,比如 SQLite。我在這篇文章 my feature test suite setup 裡描述了很多細節上的不同點。我認為相比通過提升一點速度帶來的好處,保持生產環境一致更重要。

禁用 Xdebug

如果你平時用不到 Xdebug 的話,可以禁用掉它,因為它會降低 PHP 執行速度,導致測試用例執行緩慢。如果你日常使用它來除錯的話,為了執行測試而禁用它可能不是一個好的選擇 —— 但你始終要知道這一點當你關注測試用例執行速度時。

你可以在下面這個測試用例看到,一旦我們禁用了 Xdebug,執行速度將會有極大的提高。下面是這個測試用例在 Xdebug 啟用時的執行情況:

PHPUnit 加速技巧分享

以及同樣的測試用例在 Xdebug 禁用時的執行情況:

PHPUnit 加速技巧分享

修復測試速度過慢

當然我們最希望看到的段落是是:修復測試速度過慢!如果您正在努力確定哪些測試導致測試單元變慢時,您可能需要檢視 PHPUnit Report 。它是一個開源工具,允許您通過生成如下所示的雲視覺化您的測試單元的效能,其中較大的氣泡代表慢速測試。這將使您能夠在單元中找到最慢的測試並逐步提高其效能。

file

轉自 PHP / Laravel 開發者社群 laravel-china.org/topics/2234…

相關文章