iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
1
自我挑戰組

Laravel 實戰經驗分享系列 第 19

Laravel 實戰經驗分享 - Day19 PHPUnit 如何在你的 Laravel 專案中寫測試

寫到今天進入第十九天,看來離完賽已不遠矣?
最近幾天寫到有點厭世,感覺自己其實沒有想像中有料(?),畢竟工作經驗不是非常的多,因此很多原本想講題目的也怕自己不夠了解,講不出重點,不過既然報名的組別是鐵人賽的自我挑戰組,這也是一種挑戰自我的方式吧?
看看目前的發文跟第一天規劃的大綱有什麼差別,結論是雖然有經過整理,但相較其他完整的應用方式仍過於零散,這也許是之後可以改進的地方,不過到目前為止,算是把我在 Laravel 的應用整理出基本的脈絡了,不過身為一個軟體工程師,不斷的自我學習本來就是必備的職能,繼續努力吧!

程式中的自動測試

今天我們來講 Laravel 的測試,撰寫測試我認為是一個大型系統或應用上線時必須具備的功能,小型的系統或專案也許功能不多,因此可以透過一些簡單的手動測試便可找出 bug,但當你的系統功能越來越多,且不同功能之間也許會有相依性,這時需要的測試範疇越來越廣,就需要透過程式進行自動化測試,除此之外,如果我們每次在系統上線前都需要再手動測試之前開發過的功能,也會浪費不少時間,透過自動化測試,能夠讓我們直接測試舊有功能,因為他能夠幫助你找到程式可能會出錯的地方,也能夠確保未來在不同環境中能否正常運行。

PHPUnit

Laravel 也有將 PHPUnit 放在裡面,PHPUnit 是一套協助測試 PHP 程式碼的測試框架,

  • phpunit.xml
    phpunit.xml 是 PHPUnit 的設定檔,一般都需要在裡面設定跑測試的資料夾路徑,但 Laravel 都已經寫設定完畢,因此不太需要更動到太多的設定。
  • 執行測試
    你可以直接透過 vendor/ 執行 PHPUnit,也能夠透過 Laravel Artisan 提供的指令執行
./vendor/bin/phpunit
# or
php artisan test

單元測試範例:測試註冊功能

如果我們的系統已開發好會員的註冊功能,我們可以寫入自動化測試中,之後開發新功能時不用再次測試這個地方,如果你設計的其他功能與這邊有關聯或是依賴性,導致錯誤的話,自動化測試也可以幫你找到錯誤。

設定 Testing Database

  • 一般來說,測試的時候不會使用正式資料庫進行測試,否則可能會造成正式環境的錯誤

    因此在 config/database.php 內的 connection 內增加以下內容

    'sqlite_testing'=>[
          'driver'=>'sqlite',
          'database'=>':memory:',
          'prefix'=>'',
          'foreign_key_constraints'=>true,
    ],
    

    ※註:PHPUnit 的 driver 使用 sqlite,database 則在記憶體內跑,可以大幅提升測試效率

  • phpunit.xml 建立前一步驟的 DB_CONNECTION 以及其他參數

    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="sqlite_testing"/>
        <server name="DB_DATABASE" value=":memory:"/>
        <server name="MAIL_DRIVER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
    </php>
    

測試註冊功能

  • 建立測試檔案

    php artisan make:test RegisterTest
    

    ※註:PHPUnit 的檔案結尾強制使用 Test.php

  • 測試註冊頁面,首先先列出目前被啟用的 API

    php artisan route:list
    

    再來則至 tests\Feature\RegisterTest.php 內新增以下程式碼

    public function testExample()
    {
        $response = $this->get('/');
        $response->assertStatus(200);
    }
    
  • 再來則測試註冊功能,需先了解系統的註冊流程為何

    由於每一次測試的時候都會需要新增資料,使用 use RefreshDatabase; 可以在每一次跑測試的時候刷新資料庫。 assert 是 PHPUnit 的斷言方法,詳細使用可以參照 官網文件

    以註冊流程為例,Test 可以這樣寫

    use RefreshDatabase;
        public function testRegisterPage()
        {
            $user = factory(User::class)->create();
            $this->post('/signup',[
                'email'=>$user->email,
                'password'=>'password',
                'password_confirmation' => 'password',
            ]);
    
            $this->assertDatabaseHas('users',[
                'email'=>$user->email,
            ]);
    
            $this->assertTrue(
                Hash::check('password', User::where('email', $user->email)->first()->password)
            );
        }
    
  • 進行測試

    ./vendor/bin/phpunit
    

測試覆蓋率

當你的開發越來越大,功能越來越多,到一個程度時我們需要以覆蓋率(Coverage)來確保許多必須被測試到的程式都有順利測試。

你可以到 phpunit.xmltestsuites 後加入以下的設定,這樣在每一次執行測試後,就可以到 report 內的 index.html 看你整個程式的測試覆蓋率了。

 <logging>
     <log type="coverage-html"
         target="/path/to/report"
         lowUpperBound="35"
         highLowerBound="70" />
 </logging>

但是這邊必須說,覆蓋率的多寡並不是決定一個系統在測試上的好壞,這必須分清楚,不是一味追求高覆蓋率的測試就是好測試,而是你在這個測試的過程中,是否有測到關鍵的程式碼,這才是需要撰寫自動化測試的原因,否則過度追求高覆蓋率,沒有思考後續各單元的整合性以及關鍵程式碼的測試,很容易導致以下悲劇發生。

但是測試覆蓋率過低,就是沒有好好用心設計系統啦!

明天見!


上一篇
Laravel 實戰經驗分享 - Day18 JWT 實作
下一篇
Laravel 實戰經驗分享 - Day20 Laravel 的自創型別 Collections
系列文
Laravel 實戰經驗分享30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言