PHPUnitでajaxから呼ばれるモジュール(jsonをecho)のテストをする自分の解

投稿日:

東京はサクラ咲きまくってるけど、自分の住んでいるとこ(ちば)は全然咲いていなくて春なのか春じゃないのかよく分からない今日このごろ。

話は変わって、最近やっと案件でもPHPUnit書くようになってきたんだけども(個人的には書いてたよ。ほ、本当だよ。)、どうやってテスト書けばいいねんってケースに出くわしました。

それは、ajaxから呼ばれるプログラムのテストです。
そうっすAPIっす。
返却値(大体json形式ですよね)をechoするやつっす。
echoするやつのテストどうしたらええねんってやつっす。

※こんなやつです

1
2
3
4
5
function echoJson()
{
    header("Content-Type: application/json; charset=utf-8");
    echo json_encode(array("name"=>"Bob"));
}

呼んでも値受け取れないし、むしろ怒られるし。

Cannot modify header information - headers already sent by (output started at phar:///usr/local/bin/phpunit/phpunit/Util/Printer.php:172)

ob_start()ob_clean()で囲えば怒られないけど、何か

risky tests!

って言われるし。

2016/12/14 追記

PHPUnitでheader関数を使うメソッドのテスト | Shimabox Blog に書きましたが、@runInSeparateProcessob_start()ob_get_contents()ob_end_clean()を使う方法もあります。こちらで実装すれば

risky tests!

って怒られません。

2016/12/14 追記ここまで

でも、モックを使った解決策をちょっと思いついたので記しておきます。

先にソースを

<?php
/**
* メッセージ(json)を返すAPIと仮定
*
* あくまでもサンプルなので例外処理は入れていません
*/
class Sample
{
/**
* @var array
*/
protected $messages = array(
1 => "hoge",
2 => "piyo"
);
/**
* @param int $id
*/
public function getMessage($id)
{
$message = array("message" => $this->messages[$id]);
$this->echoJson(json_encode($message));
}
/**
* @param string $massage
*/
protected function echoJson($message)
{
header("Content-Type: application/json; charset=utf-8");
echo $message;
}
}
/**
* jsonを返すAPIのテストコード
*
* @group Sample
*/
class SampleTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function echoJsonはjson_encodeされた期待値を受け取っているか()
{
// モック化
$target = $this->getMockBuilder('Sample')
->setMethods(array('echoJson'))
->getMock()
;
// 期待値
$expected = json_encode(array("message" => "hoge"));
// 振る舞い指定
$target->expects($this->any())
// echoJsonは
->method('echoJson')
// json_encodeされた値を受け取るはずやと願いを込める
->with($this->equalTo($expected))
;
// test
$target->getMessage(1);
}
}

解説

多分ソースを見れば何となく分かると思うんですけど、ミソが、単純に引数で受け取った値をecho(headerも併せて)するメソッドを作っている部分です。
上記でいうとechoJson()が該当します。

んで、モックの定義をして、expects()with()を使ってテストします。
expects($this->any())->method('echoJson')のwith($this->equalTo('hoge'))で、echoJson()は’hoge’が渡される事を期待するって感じになります。
echoJson()に’hoge’と違う値が渡されたらテストがこけます。

上記クラスでいうならば

1
$expected = json_encode(array("message" => "piyo"));

とすると、

1
2
3
4
5
6
7
Parameter 0 for invocation Sample::echoJson('{"message":"hoge"}') does not match expected value.
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'{"message":"piyo"}'
+'{"message":"hoge"}'

こうなります。

つまり、echoする関数に対してちゃんと期待通りの引数が渡っているよね。ちゃんとした値が渡っていればおkだよねって感じのテストです。

というわけで、ここまでテスト書ければいいんじゃないのかなというのが、ついさっき思いついた自分の解です。何かミスっていたらすいません。

受け取った値をechoするメソッドを持つクラスを作るやり方もあると思います(こっちだとモックらなくてもいい)が、モックりたかったので今回はこれで。

まとめ

処理を分けて、モックを使えばなんとかなる!

最近やっとモックを使ったテストを覚えてきましたが、モックまじヤバイです。パネェっす。近いうちまた何か書きます。

参考にさせて頂きました

投稿日:
カテゴリー: PHPUnitPHP

作成者: shimabox

Web系のプログラマをやっています。 なるべく楽しく生きていきたい。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください