Laravel モックを使用した単体テスト

# はじめに
モックの書き方の備忘録として。

最近はテストを書くことが当たり前になってきていると思います。
APIの連携を行う結合テストや、複数のメソッドを扱っているメソッドの単体テストではモックが必ず必要になります。
モックを扱ったことが無い方は是非使うようにしてください。

# モックとは
こちらの記事がわかりやすいと思いました。
https://qiita.com/dublog/items/803516e2ecf998230f9a


# 一番オーソドックスだと思われるやり方
早速、一例をば。

```php

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use Mockery;

class Hoge
{
    public function call()
    {
        return 'this method is called.';
    }

    public function fuga()
    {
        return 'fuga';
    }
}

class Fuga
{
    public function useHogeMethod(Hoge $hoge)
    {
        return $hoge->call();
    }
}

class SampleTest extends TestCase
{
    // Mockeryのオーソドックスなやり方
    public function testCallToMock()
    {
        // 準備
        $m = Mockery::mock(Hoge::class);
        $m->shouldReceive('call')
            ->once()
            ->andReturn('BTW...why?');
        $huga = new Fuga;

        // 実行
        $actual = $huga->useHogeMethod($m);

        // 検証
        $this->assertEquals('BTW...why?', $actual);
    }
}
```

多分、一番オーソドックスなやり方。

Laravelのリファレンスに載っているやり方だと以下になります。
但し、今のままだと二つ目のテストは失敗します。

```php
<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use Mockery;

class Hoge
{
    public function call()
    {
        return 'this method is called.';
    }

    public function fuga()
    {
        return 'fuga';
    }
}

class Fuga
{
    public function useHogeMethod(Hoge $hoge)
    {
        return $hoge->call();
    }
}

class SampleTest extends TestCase
{
    // Mockeryのオーソドックスなやり方
    public function testCallToMock()
    {
        // 準備
        $m = Mockery::mock(Hoge::class);
        $m->shouldReceive('call')
            ->once()
            ->andReturn('BTW...why?');
        $huga = new Fuga;

        // 実行
        $actual = $huga->useHogeMethod($m);

        // 検証
        $this->assertEquals('BTW...why?', $actual);
    }

    public function testCallToMockUsedLaravel()
    {
        // 準備
        // これらは上記のMockeryと同じことをしている
        // $m = $this->instance(Fuga::class, Mockery::mock(Fuga::class, function ($mock) {
        //     $mock->shouldReceive('process')->once();
        // }));
        $m = $this->mock(Hoge::class, function ($mock) {
            $mock->shouldReceive('call')
                    ->once()
                    ->andReturn('つけ麺食べたい');
        });
        $huga = new Fuga;

        // 実行
        $actual = $huga->useHogeMethod($m);

        // 検証
        $this->assertEquals('つけ麺食べたい', $actual);
    }
}

```

二つ目のテストコードの`$this->mock`では、Laravelの基底クラスを使用する必要があります。
~~私はたまにこれでエラーを出してます。~~

```php
<?php

namespace Tests\Unit;

// PHPUnitの基底クラス
// use PHPUnit\Framework\TestCase;
// Laravelの基底クラス
use Tests\TestCase;
use Mockery;

...省略
```

また、別の例として同クラス内でのメソッドの呼び出しを行う場合を挙げます。
部分的にモックしたい場合は`makepartial`を使います。

# makepartialの使い方

```php
<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use Mockery;

class Hoge
{
    public function call()
    {
        return 'this method is called.';
    }

    public function fuga()
    {
        return 'fuga';
    }

    public function hogehoge()
    {
        return $this->call();
    }
}

class SampleTest extends TestCase
{
    public function testMakePartial()
    {
        // 準備
        $m = Mockery::mock(Hoge::class)->makePartial();
        $m->shouldReceive('call')
            ->once()
            ->andReturn('testing!!!!!');

        // 実行
        $actual = $m->hogehoge();

        // 検証
        $this->assertEquals('testing!!!!!', $actual);
    }
}
```
本来、callメソッドは`this method is called.`が返り値ですがmakepartialをすることで返り値が`testing!!!!!`に差し替えられたんですね。

# まとめ
上記の様に、メソッドを仮のメソッドに差し替えたいときにはモックを扱います。
テストを書く必要が出てきたら当たり前のようにモックを使う必要があります。

よくある例として、単体テストなのに他のメソッドに依存してしまっているケースがあります。
それ、単体じゃねーから！！と突っ込まれる前に、依存している箇所はモックをしておきましょう。

# あとがき
テストフレームワークは様々なものがあります。
Laravelでは必ずPHPUnitを使う必要がある!!ではないです。
Djangoでは必ずUnitTestを使う必要がある!!でもないです。

APIのテストではkarateを使う場合もあれば、他のツールを扱う事もありますので、変にステレオタイプを持たないようにした方がいいのかなと思います。

まぁ、PHPだったらPHPUnitやっておけば問題ないんですかね！（鼻ほじ