PHPUnitのスタブをつかってみた

こんにちは。今日は空が青いです。きたけーです。

昨日、PHPUnitについて簡単に紹介しました。最後にも書きましたが、やはり気になったのはスタブとモックです。ここではあまりよい例とはいえないかもしれませんが簡単なスタブの例を紹介します。 依存する元のコードがこうだとすると、

<?php
class SomeClass
{
     public function doSomething
     {
         $client = new SomeGreatWebServiceClient();
         $client->fetchData();
     }
}

依存関係を排除するためにレガシーコード改善ガイドで紹介されている「コンストラクタのパラメータ化(394)」を適用してスタブを利用できる状態にもっていきます。

<?php
require_once './SomeGreatWebServiceClient.php';

class SomeClass
{
    private $client;

    public function __construct($client=null)
    {
        if ($client === null) {
            $this->client = new SomeGreatWebServiceClient();
        } else {
            $this->client = $client;
        }
    }

    public function doSomething()
    {
        return $this->client->fetchData();
    }
}

テストは以下のようになります。setupでスタブオブジェクトを作成してSomeClassのコンストラクタに渡しています。

<?php
require_once 'PHPUnit/Framework/TestCase.php';
require_once './SomeClass.php';
require_once './SomeGreatWebServiceClient.php';

class SomeClassTest extends PHPUnit_Framework_TestCase
{
    public function setup()
    {
        $client = $this->getMock(
            'SomeGreatWebServiceClient',
            array('fetchData')
        );

        $client->expects($this->any())
               ->method('fetchData')
               ->will($this->returnValue(array("status" => true, "data" => "...")));

        $this->some = new SomeClass($client);
    }

    public function testDoSomething()
    {
        $data = $this->some->doSomething();
        $this->assertTrue($data["status"]);
    }
}

コンストラクタのパラメータの肥大化

コンストラクタのパラメータ化(394)」を適用し続けていくと問題になるのがコンストラクタの引数の数です。依存しているクラスが多ければ多いほど引数の数は増えていきます。
ただ、参考書籍では、そんなに深刻な問題ではない、と言及されています。コンストラクタの引数となったことで何が依存していたのかが明確になりましたし、次のステップで引数に渡されているオブジェクトのクラス間の関連を見出してまとめることもできるからです。

最後の手段としてtest_helpersライブラリを使う

歴史のあるサービスでは依存関係が複雑で「コンストラクタのパラメータ化(394)」ができない場合もあるかもしれません。そのときはtest_helpersライブラリを使うとよいかもしれません。このライブラリはコンストラクタが呼ばれたときにフックをしかけてコンストラクタを切り替えたりすることができます。
ただし、このような黒魔術を使った手法は参考書籍では推奨されていません。その場しのぎにはなりますが、テストがしづらいという根本的な状況は解決されないからだと思います。

そもそもPHPUnitのモック・スタブは使うべきでない?

レガシーコード改善ガイドのp32に以下のような言及があります。

モックオブジェクトは強力なツールであり、さまざまなモックオブジェクトフレームワークが提供されています。ただし、すべての言語に対応するモックオブジェクトフレームワークがあるわけではありません。たいていの場合、単純な偽装オブジェクトで十分です。

これは特に理由が触れられていないのですが、やりたいことに対して機能が豊富すぎるのでは、と推測しています。テストハーネスとしてPHPUnitを導入するのならば、使えるものは使ってよいのでは、と個人的に思っています(バージョンアップで挙動が変わりそうな先鋭的な機能は避ける)。

参考文献

レガシーコード改善ガイド (Object Oriented SELECTION)

レガシーコード改善ガイド (Object Oriented SELECTION)

  • 作者: マイケル・C・フェザーズ,ウルシステムズ株式会社,平澤章,越智典子,稲葉信之,田村友彦,小堀真義
  • 出版社/メーカー: 翔泳社
  • 発売日: 2009/07/14
  • メディア: 大型本
  • 購入: 45人 クリック: 673回
  • この商品を含むブログ (145件) を見る
実践テスト駆動開発 テストに導かれてオブジェクト指向ソフトウェアを育てる (Object Oriented SELECTION)

実践テスト駆動開発 テストに導かれてオブジェクト指向ソフトウェアを育てる (Object Oriented SELECTION)