Phakeを試してみます

ロジックコードをテストしたいけど、EntityManager や Repository、データベースに依存している...
そんな時のモック&スタブを面倒みてくれる Phake を試してみます。

テスト対象のメソッドを含むクラス

class FooBar
{
    protected $em;

    // コンストラクタに EntityManager を渡す必要があります
    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    // このメソッドをテストしたいのです
    public function findProduct($id)
    {
        // Repository に依存しています
        $repository = $this->em->getRepository('XxxxSampleBundle:Product');

        return $repository->find($id);
    }
}

テストコード

use Xxxx\SampleBundle\Entity\Product;
use Xxxx\SampleBundle\Domain\FooBar;

class UsePhakeTest extends \PHPUnit_Framework_TestCase
{
    public function testFindProduct()
    {
        // モックオブジェクトを生成
        $mockEm = \Phake::mock('Doctrine\ORM\EntityManager');
        $mockRepo = \Phake::mock('Doctrine\ORM\EntityRepository');

        // スタブメソッドを定義 - EntityManagerのモックのgetRepository()を呼ぶと、Repositoryのモックを返します
        \Phake::when($mockEm)->getRepository(\Phake::anyParameters())->thenReturn($mockRepo);

        // スタブメソッドを定義 - Repositoryのモックのfind()を呼ぶと、ダミーのProductエンティティを返します
        \Phake::when($mockRepo)->find(\Phake::anyParameters())->thenReturn(new Product());

        // テスト対象
        $fooBar = new FooBar($mockEm);
        $actual = $fooBar->findProduct(2);

        // テスト結果を評価します
        $this->assertInstanceOf('Xxxx\SampleBundle\Entity\Product', $actual);

        // スタブメソッドの呼出を検証 - 引数 'XxxxSampleBundle:Product' で getRepository() が呼び出されたましたか?
        \Phake::verify($mockEm)->getRepository('XxxxSampleBundle:Product');

        // スタブメソッドの呼出を検証 - 引数 2 で find() が呼び出されましたか?
        \Phake::verify($mockRepo)->find(2);
    }
}

おぉー。