2019-09-29

streamWrapperを使ってphp://inputをモックする

PHPでrequestBodyがapplication/www-xxx以外のリクエスト(JSONとかXML)を処理する場合、 php://input からデータを取得することになります。

昨今のフレームワークであればリクエストに関するデータらはRequestオブジェクトなどに隠蔽されており、functional tests等でモックできるため php://input を意識することはほとんど無いと思います。

ただ、フレームワークを使わない場合は php://input を直接ハンドリングする必要があるのですが、その場合functional testsでは php://input のモックをする必要があります。

ということで今回は php://input をstreamWrapperでモックしてphpunitでテストする方法について紹介します。


以下のようなstreamWrapperなクラスを作ります。

<?php

class PHPStreamWrapper
{
    private static $content;
    private $position;

    /**
     * @param string $content
     */
    public static function setContent($content)
    {
        self::$content = $content;
    }

    public function stream_open($path)
    {
        return true;
    }

    public function stream_read($count)
    {
        $ret = substr(self::$content, $this->position, $count);
        $this->position += strlen($ret);
        return $ret;
    }

    public function stream_stat()
    {
        return [];
    }

    public function stream_eof()
    {
        return $this->position >= strlen(self::$content);
    }
}

setContentはモックする文字列をセットする関数で、それ以外はphp://inputからの読み込みで使う関数になります。 基本的にはsetContentでセットした文字列をstream_readで返していくだけ。

あとはsetUpでstream_wrapper_registerして、tearDownでstream_wrapper_restoreして元のストリーム処理に戻せばOK。

<?php

class HogeTest extends PHPUnit\Framework\TestCase
{
    public function setUp()
    {
        stream_wrapper_unregister('php');
        stream_wrapper_register('php', PHPStreamWrapper::class);
    }

    public function tearDown()
    {
        stream_wrapper_restore('php');
    }

    public function xxx()
    {
        PHPStreamWrapper::setContent('mock string');
        // 何かテスト
    }
}
このエントリーをはてなブックマークに追加