阿川私房教材:學程式,拿 offer!

63 個專案實戰,直接上手!
無需補習,按步驟打造你的面試作品。

立即解鎖你的轉職秘笈

為了提升系統穩定性,最近替某電商客戶的專案寫單元測試

有一部份核心功能會用到第三方 API,這讓測試變很難寫,因為沒有本地的狀態變化可以比較

想到 laravel 有一個關於 mail 的測試功能,有類似情況

簡單來說就是在 phpunit 中這樣啟動之後

Mail::fake();

就可以這樣來檢查是否有執行某 api

Mail::assertSent(OrderShipped::class);

能否用同樣原理,處理我面對的情況呢?

決定來看一下原始碼!


首先是 fake 會直接換掉 Mailer 的實體

framework/src/Illuminate/Support/Facades/Mail.php

    public static function fake()
    {
        $actualMailManager = static::isFake()
                ? static::getFacadeRoot()->manager
                : static::getFacadeRoot();

        return tap(new MailFake($actualMailManager), function ($fake) {
            static::swap($fake);
        });
    }

可見是實作同樣 interface 的測試專用類別!

framework/src/Illuminate/Support/Testing/Fakes/MailFake.php

然後寄信就改成,把變數存進陣列即可

    public function send($view, array $data = [], $callback = null)
    {
        if (! $view instanceof Mailable) {
            return;
        }

        $view->mailer($this->currentMailer);

        if ($view instanceof ShouldQueue) {
            return $this->queue($view, $data);
        }

        $this->currentMailer = null;

        $this->mailables[] = $view;
    }

然後 assertSent 那些就檢查陣列內容,比對一下即可

    public function assertSent($mailable, $callback = null)
    {
        [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);

        if (is_numeric($callback)) {
            return $this->assertSentTimes($mailable, $callback);
        }

        $message = "The expected [{$mailable}] mailable was not sent.";

        if (count($this->queuedMailables) > 0) {
            $message .= ' Did you mean to use assertQueued() instead?';
        }

        PHPUnit::assertTrue(
            $this->sent($mailable, $callback)->count() > 0,
            $message
        );
    }

inside of the sent function

        return $this->mailablesOf($mailable)->filter(fn ($mailable) => $callback($mailable));

所以,目前這樣看起來,在需要測試跟「第三方 API」有關的功能時,可以使用同樣原理

使用 laravel 提供的 mock 功能,把會用到的第三方套件 mock 掉,套件的核心 function 就存個變數或陣列之類的

然後多寫個類似 assertSent 這樣的方法,應該就可以做到不錯的測試效果~!

簡單來說,就是設法做出「本地的狀態變化可以比較」就是了

我來往這方向寫寫看,有心得再補充分享~


共有 0 則留言


👉 身份:資深全端工程師、指導過無數人半路出家轉職 👉 使命:打造 CodeLove 成為優質新手村,讓非本科也有地方自學&討論

阿川私房教材:學程式,拿 offer!

63 個專案實戰,直接上手!
無需補習,按步驟打造你的面試作品。

立即解鎖你的轉職秘笈