Laravel

【Laravel】 Slack通知の実装・テストコードの書き方を解説

今回はLaravelでSlack通知の実装方法、およびそのSlack通知のテストコードの書き方について解説します。

Slack通知の実装方法

Slack WebHookURLの取得

まず、SlackのWebHookURLを取得します。

以下の記事を参考に取得してください。(とてもわかりやすく書かれています)

参考:SlackのWebhook URL取得手順

Slack関連情報を.envに登録

WebHookURLが取得できたら.envに書き込みます。

// 取得したWebHookURL
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxxxxxxxxx/xxxxxxxxxx/xxxxxxxxxxxxxxxxxxx

// 通知を送信するチャンネル
SLACK_CHANNEL=#general

// 通知の送信者名
SLACK_SENDER_NAME=Slack-Notification-Bot

// 通知の送信者アイコン画像のURL
SLACK_ICON=https://s3-us-west-2.amazonaws.com/xxxxxxx/xxxxxx/xxxxxx/xxxxxxxx.png

Slack通知チャンネルの追加

Slack通知チャンネルを追加するためにcomposerパッケージをインストールします。

> composer require laravel/slack-notification-channel

Notificationクラスの作成

以下のコマンドでNotificationクラスを作成します。

> php artisan make:notification SlackNotification

app/Notifications/SlackNotification.phpというファイルが作成されますが、コードがメール通知の内容になっていますので、これを以下のようにSlack通知向けの内容に変更します。

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\SlackMessage;

class SlackNotification extends Notification
{
    use Queueable;

    protected $channel;
    protected $icon;
    protected $name;
    protected $message;

    /**
     * Create a new notification instance.
     * @return void
     */
    public function __construct($message)
    {
        // Slackに関数する情報はconfigに定義しておく
        $this->channel = config('slack.channel');
        $this->icon = config('slack.icon');
        $this->name = config('slack.sender_name');
        $this->message = $message;
    }

    /**
     * Get the notification's delivery channels.
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];
    }

    /**
     * Get the array representation of the notification.
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [];
    }

    /**
     * Get the Slack representation of the notification.
     * @param mixed $notifiable
     * @return SlackMessage
     */
    public function toSlack($notifiable)
    {
        return (new SlackMessage)
            ->from($this->name)
            ->image($this->icon)
            ->to($this->channel)
            ->content($this->message);
    }
}

__construct内でメンバ変数に代入する値は以下のようにconfigに設定しておきます。

<?php

return [
    'webhook_url' => env('SLACK_WEBHOOK_URL'),
    'channel' => env('SLACK_CHANNEL'),
    'sender_name' => env('SLACK_SENDER_NAME'),
    'icon' => env('SLACK_ICON'),
];

サービスコンテナの作成

サービスコンテナを利用してSlack通知処理の実装をしていきます。

まず、Slack通知処理を記述するサービスコンテナを作成し以下のように変更します。

<?php

namespace App\Services;

use Illuminate\Notifications\Notifiable;
use App\Notifications\SlackNotification;

class SlackNotificationService implements SlackNotificationServiceInterface
{
    use Notifiable;

    public function send($message)
    {
        $this->notify(new SlackNotification($message));
    }

    protected function routeNotificationForSlack()
    {
        return config('slack.webhook_url');
    }

    /**
     * Get the value of the notifiable's primary key.
     * ※後述するテストで必要(ないとエラーになる)
     *
     * @return mixed
     */
    public function getKey()
    {
        //
    }
}

作成したサービスコンテナと結合させるインターフェースを作成し以下のように変更します。

<?php

namespace App\Services;

interface SlackNotificationServiceInterface
{
    public function send($message);
}

作成したサービスコンテナとインターフェースを以下のように結合します。

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\SlackNotificationServiceInterface;
use App\Services\SlackNotificationService;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     * @return void
     */
    public function register()
    {
        $this->app->singleton(
            SlackNotificationServiceInterface::class,
            SlackNotificationService::class
        );
    }
}

サービスコンテナの作成は以上です。

Slack通知の送信

作成したサービスコンテナを利用する方法は、下記のようにSlackNotificationServiceInterfaceをコンストラクタインジェクションした上で、send関数を呼び出すだけです!

これだけでSlack通知の送信ができます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\SlackNotificationServiceInterface;

class SampleController extends Controller
{
    /**
     * @var SlackNotificationServiceInterface
     */
    private $slack_notification_service_interface;

    /**
     * @param SlackNotificationServiceInterface $slack_notification_service_interface
     */
    public function __construct(
        SlackNotificationServiceInterface $slack_notification_service_interface,
    ) {
        $this->slack_notification_service_interface =  $slack_notification_service_interface;
    }

    /**
     * Slack通知を送信する
     */
    public function sendSlackNotification()
    {
        $this->slack_notification_service_interface->send('こんにちは!!');
    }
}

↓のようにしっかりSlack通知が送信されています。

Slack通知の実装方法は以上です。

Slack通知のテストコード

上で作成したSlack通知機能のテストコードを実装します。

namespace Tests\Controllers;

use Tests\TestCase;
use App\Notifications\SlackNotification;
use App\Services\SlackNotificationService;
use Illuminate\Support\Facades\Notification;

class SampleControllerTest extends TestCase
{
    public function testsendSlackNotification()
    {
        /**
     * sendSlackNotificationのテスト
     *
     * @return void
     */
    public function testSendSlackNotification()
    {
        $expected_message = 'こんにちは!!';

        // Slack通知が実際に送信されないようにする
        Notification::fake();

        // Slack通知の送信回数が1回かのテスト(第3引数の数値が期待する送信回数)
        Notification::assertSentToTimes(new SlackNotificationService, SlackNotification::class, 1);

        // Slack通知に記載されている内容をテスト
        Notification::assertSentTo(
            new SlackNotificationService,
            SlackNotification::class,
            // 第一引数の$notificationはSlackNotification::classのインスタンス
            function ($notification, $channels) use ($expected_message) {
                // ReflectionClassのインスタンスを作成
                $reflected_notification = new \ReflectionClass($notification);
                // $notificationのmessageプロパティを取得
                $message_property = $reflected_notification->getProperty('message');
                // messageプロパティへのアクセスを許可
                $message_property->setAccessible(true);
                // messageプロパティの値(Slack通知に記載されている内容)を取得する
                $message = $message_property->getValue($notification);
                // messageプロパティの値が期待するメッセージと同じかをテストする
                $this->assertEquals($expected_message, $message);
                // 最後にtrueを返さないとエラーになる
                // (return $expected_message === $message; でもOK)
                return true;
            }
        );
    }
    }
}

上のテストコードを解説します。

Notification::fake();とすることで、テスト実行時はSlack通知が送信されなくなります。(テストを実行する度に毎回Slack通知が送信されたら鬱陶しいですからね。笑)

Notification::assertSentToTimes(new SlackNotificationService, SlackNotification::class, 1);ではSlack通知の送信回数が1回かをテストしています。

第3引数を2とすればSlack通知が2回送信されていることをテストします。

※Slack通知が送信されていないこと(送信回数が0回)をテストしたい場合は、Notification::assertNothingSent();でテストすることができます。

Notification::assertSentToではSlack通知に記載されている内容をテストしています。

Slack通知に記載されている内容をテストするためにはSlackNotificationクラスのmessageプロパティへアクセスする必要がありますが、messageプロパティのアクセス修飾子はprotectedのため、普通の方法ではアクセスできません。

そのため、第3引数のコールバック関数でリフレクションクラスのインスタンスを作成し、messageプロパティへのアクセスを許可する必要があります。

アクセスを許可することでmessageプロパティの値を取得でき、Slack通知に記載された内容がテストできるようになります。

Slack通知のテスト方法は以上です。

参考


Laravel 8.x 通知
Laravel 8.x モック

laravelでのSlack通知実装

【PHP】リフレクションクラスでprivate変数、privateメソッドをテストする

SlackのWebhook URL取得手順

Webエンジニア
タクマ
埼玉県出身の33歳

新卒で入社した専門商社で8年間営業職として勤務

30歳からプログラミングを始め31歳でWebエンジニアに転職成功

受託開発企業での開発を1年弱経験したのち、現在はスタートアップの自社開発企業で開発に従事している
\ Follow me /

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA