Symfony Advent Calendar 2017 6日目 の記事です。 昨日は弊社の澤井による Symfony4をインストールして”Hello World”を表示させるまでの手順 でした。

先月末、ついにSymfony3.4とSymfony4がリリースされましたね! インストール方法やディレクトリ配置もガラッと変わり、なんだか新鮮な感じがします。

さて、最新のSymfony環境で開発するときにも、テストは欠かせません。 テストと言えば機能テストを書く時のもはや定番の便利バンドル、LiipFunctionalTestBundle があります。 Symfony2.xでLiipFunctionalTestBundleを使う場合の記事は既にあるのですが、

Symfony3.4以上にはそのまま適用できず、少し設定方法が変わっていました。

そこで、 Symfony3.4 の環境でLiipFunctionalTestBundleを使って機能テストを書く方法をご紹介します。(本当はSymfony4でやりたかったのですが、 LiipFunctionalTestBundleはまだSymfony4未対応のため、泣く泣く3.4にします。)

Symfony3.4環境を作る

symfony/skeletonを使ってSymfony3.4環境を作りましょう。

$ composer create-project symfony/skeleton:"~3.4"

必要な依存ライブラリをインストール

まず、 symfony/skeleton にはphpunit/phpunitを始めとするテスト用のライブラリ群が入っていないので、機能テストを実行するのに必要なライブラリを追加します。

$ composer require simple-phpunit symfony/browser-kit:"~3.4"

次に、 LiipFunctionalTestBundleを使うのに必要なライブラリを追加します。 nelmio/alice のバージョン3.0以降とLiipFunctionalTestBundleは互換性がありませんので、 nelmio/alice のバージョン指定 ~2.0 が必要です。

$ composer require liip/functional-test-bundle nelmio/alice:"~2.0" doctrine/doctrine-fixtures-bundle hautelook/alice-bundle

prodとtestでデータベースを分けるための設定

config/packages/test/doctrine.yaml を下記の内容で作成します。

doctrine:
  dbal:
    driver: "pdo_sqlite"
    url: "sqlite:///%kernel.project_dir%/var/testdb.sqlite"

また、 hautelook/alice-bundle の設定ファイルは、デフォルトではdev用しか生成されないので、testにもコピーします。

$ cp config/packages/dev/hautelook_alice.yml config/packages/test/hautelook_alice.yml

テスト対象のエンティティとコントローラを用意

エンティティ

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Class Task
 *
 * @ORM\Entity
 * @package App\Entity
 */
class Task
{
    /**
     * @var integer
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    public $id;

    /**
     * @var string
     * @ORM\Column(type="string", length=255)
     */
    public $title;
}

コントローラ

<?php

namespace App\Controller;

use App\Entity\Task;
use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;

class TaskController
{
    /**
     * @var EntityManagerInterface
     */
    private $em;

    /**
     * @param EntityManagerInterface $em
     */
    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }


    /**
     * @Route("/task/{id}")
     * @param int $id
     * @return Response
     */
    public function showAction($id)
    {
        $task = $this->em->find(Task::class, $id);

        return new Response('task: '.$task->title);
    }
}

これで準備は完了です!

機能テストを書く

早速fixtureと機能テストを書いてみましょう。

fixture

# tests/fixtures/task.yml
App\Entity\Task:
  task1:
    title: "test1"

機能テスト

<?php

// tests/Controller/TaskControllerTest.php

namespace App\Controller;

use Liip\FunctionalTestBundle\Test\WebTestCase;

class TaskControllerTest extends WebTestCase
{
    public function setUp()
    {
        parent::setUp();

        $this->loadFixtureFiles([
            __DIR__.'/../fixtures/task.yml',
        ]);
    }

    public function test()
    {
        $client = static::createClient();
        $client->request('GET', '/task/1');

        $this->assertEquals('task: test1', $client->getResponse()->getContent());
    }
}

実行結果

$ bin/phpunit
#!/usr/bin/env php
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

Testing Project Test Suite
.                                                                   1 / 1 (100%)

Time: 653 ms, Memory: 16.00MB

OK (1 test, 1 assertion)

Remaining deprecation notices (4)

The Symfony\Bundle\FrameworkBundle\Test\KernelTestCase::getPhpUnitXmlDir() method is deprecated since 3.4 and will be removed in 4.0: 1x
    1x in TaskControllerTest::setUp from App\Controller

The Symfony\Bundle\FrameworkBundle\Test\KernelTestCase::getPhpUnitCliConfigArgument() method is deprecated since 3.4 and will be removed in 4.0: 1x
    1x in TaskControllerTest::setUp from App\Controller

The "hautelook_alice.fixtures.loader" service is private, checking for its existence is deprecated since Symfony 3.2 and will fail in 4.0: 1x
    1x in TaskControllerTest::setUp from App\Controller

The "hautelook_alice.fixtures.loader" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead: 1x
    1x in TaskControllerTest::setUp from App\Controller

テスト通りました! LiipFunctionalTestBundle内で非推奨の警告が出てますが、fixtureを使った機能テスト自体はうまく実行できています。

まとめ

本記事で使用したサンプルコードは下記レポジトリで公開しています。
https://github.com/77web/sf3.4-functional-test-sample

ちなみに、LiipFunctionalTestBundleでは現在、 Symfony4対応のPR が作業中のようですので、いずれSymfony4でも使えるようになると思われます。 楽しみですね!