【PHP】メソッドが呼び出されたことをチェックするテスト

ここではPHPUnitのモックオブジェクトを使ってメソッドが呼び出されたことをチェックします。

基本的にはPHPUnitのマニュアルに記載されているんですが、見ても分からないという人がいたので、サンプルプログラムを作成しつつ見ていこうと思います。

サンプルプログラム

呼び出される側のサンプルプログラム

他のクラス、メソッドから呼び出されるサンプルとして以下のようなクラスを用意しました。
このクラスをモックにして検証していくことになります。

<?php

class CalledClass
{
    public function calledMethod(?string $val): ?string
    {
        return $val;
    }

    public function calledMethodTwoArg(?string $val1, ?string $val2): string
    {
        return $val1 . ',' . $val2;
    }
}

呼び出す側のサンプルプログラム

呼び出す側のサンプルとして以下のようなメソッドを用意しました。

<?php

class CallClass
{

    private $called;

    public function __construct(CalledClass $called)
    {
        $this->called = $called;
    }

    public function callOnce(?string $val): ?string
    {
        return $this->called->calledMethod($val);
    }

    public function callTwice()
    {
        $this->called->calledMethod('one');
        $this->called->calledMethod('two');
    }

    public function callTwoArg(?string $val1, ?string $val2): string
    {
        return $this->called->calledMethodTwoArg($val1, $val2);
    }

    public function callTwoArgTwice(?string $val1, ?string $val2)
    {
        $this->called->calledMethodTwoArg('one', $val1);
        $this->called->calledMethodTwoArg('two', $val2);
    }
}

テストコード

メソッドが一度だけ呼び出されていることを検証するテスト

メソッドが一度呼び出されていることを確認するテストコードが以下になります。

    public function test_callOnce()
    {
        $val = 'test';

        $called = $this->createMock(CalledClass::class);

        $called->expects($this->once())
            ->method('calledMethod')
            ->with($this->equalTo($val));

        $target = new CallClass($called);

        $target->callOnce($val);
    }

上記について解説していきます。まず、以下でモックのオブジェクトを生成しています。

$this->createMock(CalledClass::class)

次に

$called->expects($this->once())

で検証するメソッドの呼び出し回数を指定しています。今回はonceで1回呼び出されることを期待しています。そして、

->method('calledMethod')

は対象のメソッド名を指定しており、

->with($this->equalTo($val));

は呼び出し時の引数を指定しています。

メソッドが指定回数だけ呼び出されていることを検証するテスト

メソッドが指定回数だけ呼び出されていることを確認するテストコードが以下になります。

    public function test_callTwice()
    {
        $called = $this->createMock(CalledClass::class);
        $called->expects($this->exactly(2))
            ->method('calledMethod')
            ->withConsecutive([$this->equalTo('one')], [$this->equalTo('two')]);

        $target = new CallClass($called);

        $target->callTwice();
    }

こちらも解説していきます(ただし、先ほどと同じ部分は省きます)。
まず、

$called->expects($this->exactly(2))

は先ほどと同様に検証するメソッドの呼び出し回数を指定しています。exactlyは呼び出しの回数を引数で指定します。このケースでは2回の呼び出しを期待しています。そして

->withConsecutive([$this->equalTo('one')], [$this->equalTo('two')]);

は呼び出し時の引数を指定しています。今回は複数回呼び出すため、先ほどとは違いwithConsecutiveというメソッドを使っています。

メソッドの引数の数に合わせた配列(今回は対象メソッドの引数が1つなので要素1の配列)をメソッドの呼び出し回数分指定しています。

メソッドの引数の値を検証するテスト

メソッドが呼び出された時の引数の値を確認するテストコードが以下になります。

    public function test_callTwoArg()
    {
        $arg_1 = 'hoge';
        $arg_2 = 'fuga';

        $called = $this->createMock(CalledClass::class);
        $called->expects($this->once())
            ->method('calledMethodTwoArg')
            ->with($this->equalTo($arg_1), $this->equalTo($arg_2));

        $target = new CallClass($called);

        $target->callTwoArg($arg_1, $arg_2);
    }

今回は1回呼び出しなので、最初と同様に

$called->expects($this->once())

としています。そして

->with($this->equalTo($arg_1), $this->equalTo($arg_2));

で呼び出し時の引数を指定しています。最初のケースとは違い、withの引数の数がテスト対象のメソッドの引数の数に合わせて複数(2つ)になっています。

メソッドの引数の値を複数回呼び出しで検証するテスト

メソッドが呼び出された時の引数の値を複数回呼び出しのそれぞれについて確認するテストコードが以下になります。

    public function test_callTwoArgTwice()
    {
        $arg_1 = 'hoge';
        $arg_2 = 'fuga';

        $firstArgs = ['one', $arg_1];
        $secondArgs = ['two', $arg_2];

        $called = $this->createMock(CalledClass::class);
        $called->expects($this->exactly(2))
            ->method('calledMethodTwoArg')
            ->withConsecutive($firstArgs, $secondArgs);

        $target = new CallClass($called);

        $target->callTwoArgTwice($arg_1, $arg_2);
    }

基本的には今までの組み合わせになっています。まず

$called->expects($this->exactly(2))

は呼び出し回数の指定です。上記は2回の呼び出しを期待しています。そして

->withConsecutive($firstArgs, $secondArgs);

で呼び出し時の引数を指定しています。型が分かりやすいように

$firstArgs = ['one', $arg_1];
$secondArgs = ['two', $arg_2];

のように一旦変数に置いていますが、直接指定しても大丈夫です。

作成物

今回載せたサンプルやテストコードは以下に置いています。

https://github.com/masaki-code/php/tree/master/mock

コメント

タイトルとURLをコピーしました