読者です 読者をやめる 読者になる 読者になる

Symfony2のCrawlerオブジェクトを使う

Symfony

ここに書いてあるとおり、Crawlerオブジェクトのインスタンスを直接作れば、HTMLを直接与えてテストができるようだ。

うまく使えば、Symfony2アプリケーションではないPHPアプリケーションのFunctional Testも構成できそうな気がする。(これが目的で突然Symfony2を調べ出したわけだが。)

<?php

namespace Application\HelloBundle\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\DomCrawler\Crawler;

class MyTest extends WebTestCase
{
    public function testHtml()
    {
        $html = '<html><body><ul><li class="odd">spam</li><li class="even">egg</li><li class="odd">ham</li></ul></body></html>';
        $crawler = new Crawler($html, 'http://localhost/');
        $element = $crawler
            ->filter('li')
            ->reduce(function ($node, $i) {
                    if ($node->getAttribute('class') !== 'even') {
                        return false;
                    }
                })
            ->first();
        $this->assertEquals($element->text(), 'egg');
    }
}

もうちょっと良いコード。Symfony\Component\BrowserKit\ClientのdoRequestメソッドを実装すればよいらしい。もう一つ、$client->insulate(true)をセットして、getScriptメソッドをオーバーライドするという方法もあるが、こっちは別プロセスで実行されるという違いはあるものの、Symfonyの必要なクラスをrequireしなくてはいけないということでちょっと割に合わないと感じる。

<?php

namespace Perezvon;

use Symfony\Component\BrowserKit\Client as BaseClient;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response;

class Client extends BaseClient
{
    protected function doRequest($request)
    {
        $content = '<html><body><ul><li class="odd">SPAM</li><li class="even">EGG</li><li class="odd">HAM</li></ul></body></html>';
        $response = new Response($content);
        return $response;
    }
}

class MyTest extends \PHPUnit_Framework_TestCase
{
    public function testHtml()
    {
        $client = new Client();
        //$client->insulate(true);

        $crawler = $client->request('GET', '/');
        $element = $crawler
            ->filter('li')
            ->reduce(function ($node, $i) {
                    if ($node->getAttribute('class') !== 'even') {
                        return false;
                    }
                })
            ->first();
        $this->assertEquals($element->text(), 'EGG');
    }
}