次のようなクラスがあったとして、
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();