PHPメンターズの後藤です。クリスマスまでの24日間をSymfonyの記事で楽しもう!というSymfony Advent Calendar JP 2011の3日目の記事です。

PHPメンターズって何?については、明日のSymfony勉強会で少しお話させていただく予定です。

みなさん、Symfony2本体のソースコードやテストコードを読んだことはありますか? Symfony2本体は、コアコンポーネント、コアバンドル等で成り立っており、それぞれ独立したテストコードが付属しています。PHPUnitのモックオブジェクト等を使ったテストがふんだんにあり、レイヤー化されたコンポーネントのテスト方法の参考になります。

今回は、Symfony Componentの中核をなす「HttpKernel」コンポーネントの中の、Kernelクラスのテストを1つ見てみましょう。

tests/Symfony/Tests/Component/HttpKernel/KernelTest.php:

<?php
// snip
namespace Symfony\Tests\Component\HttpKernel;

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Config\Loader\LoaderInterface;

class KernelTest extends \PHPUnit_Framework_TestCase
{
    // snip
    public function testBootInitializesBundlesAndContainer()
    {
        $kernel = $this->getMockBuilder('Symfony\Tests\Component\HttpKernel\KernelForTest')
            ->disableOriginalConstructor()
            ->setMethods(array('initializeBundles', 'initializeContainer', 'getBundles'))
            ->getMock();
        $kernel->expects($this->once())
            ->method('initializeBundles');
        $kernel->expects($this->once())
            ->method('initializeContainer');
        $kernel->expects($this->once())
            ->method('getBundles')
            ->will($this->returnValue(array()));

        $kernel->boot();
    }

このコードではKernelクラスのboot()メソッドをテストしていますが、その中でもboot()メソッドの基本的な振舞をテストしている部分です。上記コードからは、boot()メソッドの基本的な振舞は次の内容だということになります。

  • initializeBundles()メソッドを呼び出す
  • initializeContainer()メソッドを呼び出す
  • getBundles()メソッドを呼び出す

このような振舞をテストするために、PHPUnitのモックオブジェクトの機能が使われています。 モックオブジェクトを使うことで、期待するメソッドが呼び出されたどうかをテストすることができるようになります。

この例では、テスト対象となるメソッドのクラス(Kernelクラス)自身をモックオブジェクトにしていますが、一般的にモックオブジェクトが必要となるのは、テスト対象のクラス/メソッドで依存している別のクラスがある場合です。それらをモックオブジェクトで置き換え、依存メソッドの呼び出しをエミュレートするとともに、意図したとおりに呼び出されたことも検査できます。

このように、テストにおいて単に対象メソッドの入出力だけを検査するのではなく、モックオブジェクトを使ってメソッドの振舞の部分もテストで表現できるようになるのです。モックオブジェクトを使ったテストコードを読みこなせるようになれば、Symfonyのテストコードをサクサクと理解できるようになり、それぞれのコンポーネントがどういった意図を持って作られているのかといったことについても理解が進むようになります。

参考

Symfony Advent Calendarの明日の担当は、最近Symfony2の使い方ブログなどを書かれているtaka512さんです! Advent Calendarの記事を自分も書いてみたいという方は、こちらで今からでもご登録ください。