_ Mockeyで部分的にmethodを差し替えてテストする
結論だけ書くと超単純で、マニュアルのままなのですが、何故かはまったのでメモです。
以下のようなメソッドをテストしたいとします。
1
2
3
4
5
6
7
8
9
10
11
12
13
| namespace App\Http\Manager;class MyClass { function doSomething(){ if($this->add(1,2)==3){ return true; } else { return false; } } protected function add($a,$b) { return $a+$b; }}
|
doSomething()のif文が成功したパターンと失敗したパターンを試験したいのですが、失敗したパターンを発生させることができません。(あくまで例です(^^;)、本当にあり得ないのであればコードを削除しましょう)
この場合、phpUnitのMockでは以下のように書けます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| namespace tests\Unit; use App\Http\Manager\MyClass;use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;use Tests\TestCase; class MyTest extends TestCase { use MockeryPHPUnitIntegration; public function testMyClass() { // 成功 $myclass = new MyClass(); $result = $myclass->doSomething(); $this->assertTrue($result); // 失敗 $mock = $this->createPartialMock(MyClass::class, ['add']); $mock->expects($this->once())->method('add')->willReturn(0); /** @noinspection PhpUndefinedMethodInspection */ $result = $mock->doSomething(); $this->assertFalse($result); }}
|
また、Laravelに標準でバンドルされているMockeryでは以下のように書けます。
1
2
3
4
5
6
| // 失敗 $mock = \Mockery::mock('App\Http\Manager\MyClass')->makePartial()->shouldAllowMockingProtectedMethods(); $mock->shouldReceive('add')->andReturn(0); /** @noinspection PhpUndefinedMethodInspection */ $result = $mock->doSomething(); $this->assertFalse($result);
|
Mockeryの方はテスト対象クラスをフルパスで指定しています。
いずれもPartial(部分的)なmockですので、shouldReceiveで定義された差し替えるメソッド以外はMyClassのオリジナルのものがそのまま実行されます。
$mockには、クラスMyClassのメソッドがそっくり継承されているので、22行目で$mockを使ってdoSomething()を呼び出します。
簡単、明快。
ただ、Mockeryだからこそできることというのがいまいち良く分かってない・・・。
実は外部メソッドを呼んでいる処理のテストでoverloadを使おうとしたのですが、LaravelのFWによってautoloadされてしまうためか class already exists が出て使用できませんでした。アノテーションを入れても今度は $name must not be null が出てしまって解決策が見つかっていません。