iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 24
2
Modern Web

使用 Laravel 打造 RESTful API系列 第 24

讓你的程式更美好 - 寫一點點測試

  • 分享至 

  • xImage
  •  

使用Laravel 8 PHP主流框架打造RESTful API(iT邦幫忙鐵人賽系列書)ISBN:9789864345304

本系列文章已集結成冊與鐵人賽文章差異內容,有以下幾點:

更新至Laravel 8、基礎的PHP重點筆記、加強製作API流程細節、加入程式設計模式,優化、重構程式碼的部分,並且於書籍前面的章節介紹Git。

讓您從製作第一個簡單的API到優化自己的程式碼,分享我的經驗給您,打造自己的最強大腦API,若有興趣的朋友可以參考看看

天瓏網路書局:
https://www.tenlong.com.tw/products/9789864345304


此篇文章同步發於個人部落格

昨天簡單介紹一下 Service 怎麼那麼突然要寫測試!小弟我對於測試這東西也是超級初心者~但是因為維護上遇到了一些困擾,所以對於這方面開始暸解一下~

發現對於CI/CD 還蠻有興趣的,打算有時間的話可以嘗試看看有沒有機會導入公司的開發維護流程

因為遇到的困難

  • 因為需求變更修改輸出結果!發現一些必要值移除了,有些畫面顯示不出來~發生錯誤。
  • 改了這個功能沒事正常運作,但是改A壞B,另外一個功能因為有用到相關的值導致錯誤

因此來寫一點點測試吧!確保資料是我們要的樣子,測試輸出結果。

讓程式幫我們測試我們的功能,我們是開發API想必會給其他人介接API,跑測試若是減少到必要資料時就會提醒有錯誤,可以避免如果做了一些變動,不知道介接API的人用到哪些參數值,因為有測試確保錯誤的發生!

另外一個關鍵適當的用版本號控管,這必須看開發時的時間點,有不同的解決辦法,正式開發中的API就不用太在意URI的版本號了!正式上線後有人開始使用API,有改到資料的結構,建議直接用版本號去更新,就別動舊的API不然很多人用時,你可以會被很多人關心。

測試檔案命名規則

  1. 檔案一定要由Test結尾才會讀取得到!(例如下方產生的AnimalTest
  2. 檔案內的方法必須由test開頭才可以!

產生測試檔案

產生一個用來測試動物資源的測試檔案

php artisan make:test AnimalTest

準備來寫測試囉!打開 tests/Feature/AnimalTest.php

寫測試時間

這個檔案中,請自行對於想測試的動作做命名,要想想各種可能,例如我想要測試查詢動物的API,因為查看動物不需要任何權限,因此我們的程式碼相對比較簡單,我們繼續看下去吧!

測試查詢 animal 結構

/**
* 測試查看animal 列表的 json 格式
*
* @return void
*/
public function testViewAllAnimal()
{
    //請求 api/animal 結果存入 $response
    $response = $this->get('api/animal');

    //assertJsonStructure 判斷 Json 結構是否與我們下方的結構相同
    $response->assertJsonStructure([
        "current_page",
        "data" => [
            [
                "id",
                "type_id",
                "name",
                "birthday",
                "area",
                "fix",
                "description",
                "personality",
                "created_at",
                "updated_at",
                "user_id"
            ]
        ],
        "first_page_url",
        "from",
        "last_page",
        "last_page_url",
        "next_page_url",
        "path",
        "per_page",
        "prev_page_url",
        "to",
        "total",
    ]);
}

這時候你會發現左側測試套件的工具列會出現tests/Feature/AnimalTest.php 並且可以點開 有testViewAllAnimal 方法! 如下圖灰色圖示的兩個項目

套件畫面

點選 三角形執行測試,如果程式寫對,輸出結果跟剛剛撰寫的測試結構一樣,就會顯示綠色勾勾!

套件畫面

再來想想有什麼需要測試

測試創建 animal 資源

在新建前因為確保每次測試完都可以成功,不是跑第一次後第二次就不成功,或是這台機器可以跑並且全數通過,但其他機器不能跑的情況!

Laravel 有一個方便的重置資料庫的trait,不過這是會直接執行 php artisan migrate:refresh 初始化資料庫「請勿正式環境使用不然你會後悔

use Illuminate\Foundation\Testing\RefreshDatabase;

class AnimalTest extends TestCase
{
    use RefreshDatabase;

    //...
}

另外一種是 DatabaseTransactions 他是使用資料庫 Transactions 執行完後並不會提交,會rollback ,所以只會還原這是的變更!我另外一系列的鐵人賽有講到這個在附上連結!

所以我們不用上面的RefreshDatabase用DatabaseTransactions 請自行依照你的測試流程斟酌使用

use Illuminate\Foundation\Testing\DatabaseTransactions;

class AnimalTest extends TestCase
{
    use DatabaseTransactions;

    //...
}

測試有權限有效 token創建資源

因為創建這部分,管理員跟一般會員都可以操作所以寫一個就好,Passport 套件有一個方法讓我們可以模擬權限

先在tests/Feature/AnimalTest.php新建一個 testCanCreateAnimal() 我先把官方網站的範例複製過來,修改成新建動物的請求POST /api/animal其他先不改,儲存並點選執行測試的三角形按鈕,除了工具列的顯示,還會發現錯誤標示於錯誤的方法上。

測試錯誤

錯誤訊息的意思是說測試結果請求POST /api/animal 回傳 401 HTTP 狀態碼,不是 201 新建成功的狀態碼。

因為我們還沒加上模擬權限的部分,請如下修改


    /**
    * 測試建立animal
    *
    * @return void
    */
    public function testCanCreateAnimal()
    {
        Passport::actingAs(
            User::first(),
            ['*']
        );

        // 請求時並傳入資料
        $response = $this->json(
            'POST', 'api/animal', 
            [
                'type_id' => '1',
                'name' => '大黑',
                'birthday' => '2019-10-05', //今天要補班
                'area' => '台北市',
                'fix' => '1'
            ]
        );
        
        //檢查返回資料
        $response->assertStatus(201)  //狀態碼應屬於201
            ->assertJson(
                [
                    "type_id"=> "1",
                    "name"=>"大黑",
                    "birthday"=>"2019-10-05",
                    "area"=>"台北市",
                    "fix"=>"1"
                ]
            );
    }

順利通過測試,這邊用 assertJson 來檢查回傳資料是否完全符合,裡面沒有包含到的就不會去檢查,例如他會回傳 created_at、updated_at、id 沒有寫在這個陣列裡,就不會去檢查它的值,這點必須留意一下。

測試沒有有效 token 操作 測試

多增加一個 testCanNotCreateAnimal 方法,程式碼如下所示

    /**
     * 測試不能建立animal
     *
     * @return void
     */
    public function testCanNotCreateAnimal()
    {
        // 沒有模擬會員權限的程式

        // 請求時並傳入資料
        $response = $this->json(
            'POST', 'api/animal', 
            [
                'type_id' => '1',
                'name' => '大黑',
                'birthday' => '2019-10-05', //今天要補班
                'area' => '台北市',
                'fix' => '1'
            ]
        );
        
        //檢查返回資料
        $response->assertStatus(401)  //沒有token,狀態碼應屬於401
            ->assertJson(
                [
                    "message" => "Unauthenticated."
                ]
            );
    }

其他想到可以測試的功能

大部分都是這樣寫,以此類推,主要是要想辦法讓每一台伺服器跑測試的結果都一樣,並不是這台測試正確就好。以下列出還可以寫的測試,有興趣可以多多嘗試,這裡不一一列出程式碼。

  • 更新 animal 測試
    * 測試 管理員 更新
    * 測試 一般會員 更新
    * 測試 沒有有效 token 操作 更新
  • 刪除 animal 測試
    * 測試管理員 刪除
    * 一般會員 刪除
    * 沒有有效 token 操作 測試

存檔自動測試

如果你是自己撰寫程式碼多多少少會有錯誤,一直按三角形執行測試是不是覺得很煩呀~ 工程師就是最不喜歡重複的動作了!這個套件可以監測檔案儲存,自動執行測試喔!

套件畫面

現在只要儲存就會自動跑測試~ 爽~~

結論

寫測試有涵蓋率這種東西,沒有寫到測試的地方還是測不到,但我覺得核心有顧好!錯誤自然就會減少!大家一起加油吧~我也在學習,再次強調,小弟我這方面非常淺,歡迎給我任何回應!可以讓我作為改善的參考!或有什麼推薦的教學也歡迎跟我分享喔! 感謝

參考資料

Passport 模擬權限

Laravel官方測試文件


上一篇
讓你的程式更美好 - Service 概念
下一篇
讓你的程式更美好 - 重構現有的程式碼
系列文
使用 Laravel 打造 RESTful API30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言