Featured image of post PHPのライブラリを作る場合はProphecyじゃなくてPHPUnit標準のmockでいいかなと思った

PHPのライブラリを作る場合はProphecyじゃなくてPHPUnit標準のmockでいいかなと思った

Twitter ツイート Hatena Bookmark ブックマーク

PHPUnit11でProphecyを使おうと思ったら使えなかったのが事の発端です。

ただし、現在はphpspec/prophecy-phpunitのv2.2.0が出たのでphpunit11でもProphecy使うことが出来ます。

なぜPHPUnit11だとProphecyが使えないのか?

phpspec/phpunit-prophecyはv2.1.0までphpunit11に対応していませんでした。
https://github.com/phpspec/prophecy-phpunit/blob/29f8114c2c319a4308e6b070902211e062efa392/composer.json#L19

composerでprophecy-phpunitをインストールすると以下のようなエラーが発生していました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ composer require phpspec/prophecy-phpunit:v2.1.0 -W

./composer.json has been updated/phpunit-test  composer require phpspec/prophecy-phpunit:v2.1.0
Running composer update phpspec/prophecy-phpunit --with-all-dependencies
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires phpspec/prophecy-phpunit v2.1.0 -> satisfiable by phpspec/prophecy-phpunit[v2.1.0].
    - phpspec/prophecy-phpunit v2.1.0 requires phpunit/phpunit ^9.1 || ^10.1 -> found phpunit/phpunit[9.1.0, ..., 9.6.17, 10.1.0, ..., 10.5.11] but it conflicts with your root composer.json require (^11.0).

そもそもphpunitのMockでいいのでは?

Prophecyが使えないので仕方なくphpunitのMockを使ったんですが、ぜんぜん使いやすくてこれでいいやってなりました。
はるか昔phpunitのMockが使いづらくてなんだかんだでProphecy使うようになったのですが、久しぶりにPHPUnitのMock使ったら全然これでいいやってなりました。

phpunitを使ったMockとprophecyを使った比較

 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
27
28
29
30
31
32
33
<?php

declare(strict_types=1);

namespace Printgraph\PhpSdk\Tests\Client;

use GuzzleHttp\ClientInterface as HttpClientInterface;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Psr\Http\Message\ResponseInterface;

final class ClientTest extends TestCase
{
    use ProphecyTrait;  

    public function testRequestFailure(): void
    {
        // phpunit標準のmock
        $httpClientPhpUnitMock = $this->createMock(HttpClientInterface::class);
        $httpClientPhpUnitMock->expects($this->once())
            ->method('request')
            ->with('GET', '/v1/test', [])
            ->willReturn(new Response(500, [], 'error'));

        // prophecyのmock
        $httpClientProphecyMock = $this->prophesize(HttpClientInterface::class);
        $httpClientProphecyMock
            ->request('GET', '/v1/test', [])
            ->willReturn(new Response(200, [], 'test'))
            ->shouldBeCalledOnce();
    }
  }

純粋なspy方式のテストは書けない

phpunit標準のmockでは純粋なspy方式のテストは書くことが出来ません。 メソッドの引数に応じて、コール回数を取るみたいなテストは書けないようです。

メソッドの呼ばれた回数をあとから確認すること程度なら実装は可能です。

1
2
3
4
5
6
7
$httpClientPhpUnitMock = $this->createMock(HttpClientInterface::class);
$httpClientPhpUnitMock->expects($spy = $this->any())
    ->method('request')
    ->with('GET', '/v1/test', [])
    ->willReturn(new Response(500, [], 'error'));

self::assertCount(1, $spy->numberOfInvocations());

まとめ

  • 自分でphpのライブラリを作るならProphecy使わなくてもphpunitのmockで十分
  • ただしspy方式のテストが必要な場合はProphecyだったりMockeryだったりリッチなテストライブラリが必要
comments powered by Disqus
Built with Hugo
テーマ StackJimmy によって設計されています。