如何在 PHP 中測試 Trait

程式技術
sharkHead

在使用 Laravel Livewire 的時候,我時常會把 livewire component 中可以重複使用的邏輯或是方法抽出並放在 Trait 中。

Laravel Livewire 官方文件中也建議使用 Trait 來處理經常重複使用的邏輯。詳細可以參考下面兩個連結。

例如我有一個將 Markdown 轉換為 HTML 的方法,因為有很多 livewire component 都會使用到這個方法,所以我將這個方法放到 trait 中。

<?php

namespace App\Http\Traits\Livewire;

use Illuminate\Support\Str;

trait MarkdownConverter
{
    public function convertToHtml(string $body): string
    {
        $html = Str::of($body)->markdown([
            'html_input' => 'strip',
        ]);
    }
}

當我想在 livewire component 中使用這個方法時,只要簡單的使用 use 引入即可。

<?php

namespace App\Http\Livewire\Comments;

// ...
use App\Http\Traits\Livewire\MarkdownConverter;

use Livewire\Component;

class Comment extends Component
{
    use MarkdownConverter;

    // ...
    
    public function getConvertedBodyProperty(): string
    {
        return $this->convertToHtml($this->body);
    }
    
    // ...
}

Trait 用多了之後也讓我遇到一個問題。

那如果我想測試 trait 中的方法,可以怎麼做呢?

以下的測試範例皆使用 Pest,是一個建構於 PHPUnit 上的測試框架。

在測試中使用 use 引入

我們可以在測試中使用 use 將 Trait 引入,這樣就可以直接使用 Trait 中的方法。

use App\Http\Traits\Livewire\MarkdownConverter;

// 使用 use 引入 trait
uses(MarkdownConverter::class);

it('can convert the markdown content to html', function () {
    $body = '# Header 1'

    // 引入後 trait 就可以在測試中使用 convertToHtml() 方法
    $convertedBody = $this->convertToHtml($body);

    expect($convertedBody)
        ->toContain('<h1>Header 1</h1>')
});

使用匿名類別

使用 PHP 的匿名類別,簡單的建立一個實例,並在實例中使用 use 引入 Trait,在之後的測試中,我們就可以使用實例來呼叫 trait 中的方法。

use App\Http\Traits\Livewire\MarkdownConverter;

it('can block the header tag', function () {
    // 使用匿名類別建立一個引入 trait 的實例
    $trait = new class
    {
        use MarkdownConverter;
    };

    $body = '# Header 1'

    $convertedBody = $trait->convertToHtml($body);

    expect($convertedBody)
        ->toContain('<h1>Header 1</h1>')
});

使用 PHPUnit 的 getObjectForTrait 方法

與剛剛的方法類似,我們可以使用 PHPUnit 提供 getObjectForTrait() 方法來取得引入 trait 後的實例。

use App\Http\Traits\Livewire\MarkdownConverter;

it('can block the header tag', function () {
    // 透過 PHPUnit 的 getObjectForTrait() 方法取得引入 trait 的實例
    $trait = $this->getObjectForTrait(MarkdownConverter::class);

    $body = '# Header 1'

    $convertedBody = $trait->convertToHtml($body);

    expect($convertedBody)
        ->toContain('<h1>Header 1</h1>')
});

參考資料

sharkHead
written by
sharkHead

後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

1 則留言
訪客 2023 年 04 月 09 日

太讚了!!