LoginSignup
21
18

More than 5 years have passed since last update.

PHPUnit/Phake のモックで、あるメソッドが異なる引数で複数回呼ばれることをテスト

Posted at

次のようなクラスがあったとして、

class Hoge
{
    public function func($v) {}
    public function xxxx() {}
}

Hoge をモック化して func が次のように呼ばれることをテストする。

  • 引数 'A' で 1 回
  • 引数 'B' で 2 回

Phake ならこのように書ける(Phake::times(1) は省略可能)。

$hoge = Phake::mock('Hoge');

$hoge->func('A');
$hoge->func('B');
$hoge->func('B');

Phake::verify($hoge, Phake::times(1))->func(identicalTo('A'));
Phake::verify($hoge, Phake::times(2))->func(identicalTo('B'));

これは次のテストとなる。

  • func が 'A' を引数に呼ばれる回数が 1 回
  • func が 'B' を引数に呼ばれる回数が 2 回

Phake::inOrder で呼び出し順のテストも可能。

$hoge = Phake::mock('Hoge');

$hoge->func('A');
$hoge->func('B');
$hoge->func('B');

Phake::inOrder(
    Phake::verify($hoge, Phake::times(1))->func(identicalTo('A')),
    Phake::verify($hoge, Phake::times(2))->func(identicalTo('B')),
    Phake::verify($hoge, Phake::times(2))->func(identicalTo('B'))
);

前後や間に別のメソッド呼び出しがあっても大丈夫。

$hoge = Phake::mock('Hoge');

$hoge->xxxx();
$hoge->func('A');
$hoge->xxxx();
$hoge->func('B');
$hoge->xxxx();
$hoge->func('B');
$hoge->xxxx();

Phake::inOrder(
    Phake::verify($hoge, Phake::times(1))->func(identicalTo('A')),
    Phake::verify($hoge, Phake::times(2))->func(identicalTo('B')),
    Phake::verify($hoge, Phake::times(2))->func(identicalTo('B'))
);

ぱっとみ 'B' を引数に 4 回呼んでいるテストに見えるのが微妙なところ。


Phake に慣れているためか、PHPUnit のモックで同じことをやろうとして次のように書いてしまう。

$hoge = $this->getMock('Hoge');

$hoge->expects(exactly(1))->method('func')->with(identicalTo('A'));
$hoge->expects(exactly(2))->method('func')->with(identicalTo('B'));

$hoge->func('A');
$hoge->func('B');
$hoge->func('B');

これは次のテストになり成立しない。

  • func が 1 回呼ばれてその引数は 'A'
  • func が 2 回呼ばれてその引数は 'B'

次のように at を使わなければならない。

$hoge = $this->getMock('Hoge');

$hoge->expects(at(0))->method('func')->with(identicalTo('A'));
$hoge->expects(at(1))->method('func')->with(identicalTo('B'));
$hoge->expects(at(2))->method('func')->with(identicalTo('B'));

$hoge->func('A');
$hoge->func('B');
$hoge->func('B');

これは次のテストとなる。

  • 0 回目の呼び出しは func で 引数は 'A'
  • 1 回目の呼び出しは func で 引数は 'B'
  • 2 回目の呼び出しは func で 引数は 'B'

func の N 回目の呼び出し ではないので、他のメソッド呼び出しが前や間にあると at の値も変更しなければならない。

$hoge = $this->getMock('Hoge');

$hoge->expects(at(1))->method('func')->with(identicalTo('A'));
$hoge->expects(at(3))->method('func')->with(identicalTo('B'));
$hoge->expects(at(5))->method('func')->with(identicalTo('B'));

$hoge->xxxx();
$hoge->func('A');
$hoge->xxxx();
$hoge->func('B');
$hoge->xxxx();
$hoge->func('B');
$hoge->xxxx();

func だけをモック化すれば func の N 回目の呼び出し にすることもできる。

$hoge = $this->getMock('Hoge', ['func']);

$hoge->expects(at(0))->method('func')->with(identicalTo('A'));
$hoge->expects(at(1))->method('func')->with(identicalTo('B'));
$hoge->expects(at(2))->method('func')->with(identicalTo('B'));

$hoge->xxxx();
$hoge->func('A');
$hoge->xxxx();
$hoge->func('B');
$hoge->xxxx();
$hoge->func('B');
$hoge->xxxx();
21
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
18