8. 8日目: 単体テスト(ユニットテスト)

  • この記事は Symfony 1.4 向けのオリジナルの Jobeet Tutorial の一部分です。

8.1. Symfony のテスト

Symfony においての自動化されたテストには単体テスト(ユニットテスト)と機能テスト( functional test )の2種類があります。
単体テストは、各メソッドと機能が正常に動作していることを確認します。各テストは、他のものから、可能な限り独立していなければなりません。
一方で、機能テストはアプリケーションの結果が、全体として正しく動作することを確認します。
今日は単体テストを説明し、明日は機能テストに専念します。
Symfony2 は独立したライブラリであり、豊富なテスト·フレームワークを提供する PHPUnit と統合されています。
テストを実行するには、 PHPUnit の 3.5.11 以降をインストールする必要があります。

Note

PHPUnit がインストールされていない場合は、以下を使用します。

$ sudo apt-get install phpunit
$ sudo pear channel-discover pear.phpunit.de
$ sudo pear channel-discover pear.symfony-project.com
$ sudo pear channel-discover components.ez.no
$ sudo pear channel-discover pear.symfony.com
$ sudo pear update-channels
$ sudo pear upgrade-all
$ sudo pear install pear.symfony.com/Yaml
$ sudo pear install --alldeps phpunit/PHPUnit
$ sudo pear install --force --alldeps phpunit/PHPUnit
各テスト(単体テストおよび機能テスト) はバンドルのサブディレクトリ Tests/ におかれる PHP のクラスです。
この設置場所のルールに沿っている場合は、次のコマンドを使用して、すべてのアプリケーションのテストを実行することができます。
$ phpunit -c app/
-c オプションは、設定ファイルのためのディレクトリ app/ を参照するように PHPUnit に指示します。
PHPUnit のオプションについて興味があるなら、 app/phpunit.xml.dist ファイルを確認してください。
単体テスト(ユニットテスト)は、通常、特定の PHP クラスに対するテストです。 Jobeet::slugify() メソッドのためのテストを書くことから始めましょう。
src/Ibw/JobeetBundle/Tests/Utils フォルダに新しいファイル、 JobeetTest.php を作成します。
慣例により、 Tests/ のサブディレクトリは、バンドルのディレクトリ構成を複製する必要があります。
バンドルのディレクトリ Utils/ のクラスをテストするときは、ディレクトリ Tests/Utils/ にテストを置おきます。

src/Ibw/JobeetBundle/Tests/Utils/JobeetTest.php

<?php
namespace Ibw\JobeetBundle\Tests\Utils;

use Ibw\JobeetBundle\Utils\Jobeet;

class JobeetTest extends \PHPUnit_Framework_TestCase
{
    public function testSlugify()
    {
        $this->assertEquals('sensio', Jobeet::slugify('Sensio'));
        $this->assertEquals('sensio-labs', Jobeet::slugify('sensio labs'));
        $this->assertEquals('sensio-labs', Jobeet::slugify('sensio labs'));
        $this->assertEquals('paris-france', Jobeet::slugify('paris,france'));
        $this->assertEquals('sensio', Jobeet::slugify(' sensio'));
        $this->assertEquals('sensio', Jobeet::slugify('sensio '));
    }
}

このテストのみを実行するには、次のコマンドで行います。

$ phpunit -c app/ src/Ibw/JobeetBundle/Tests/Utils/JobeetTest

すべてが正常に動作するとき、次のような結果を得るでしょう:

PHPUnit 3.7.22 by Sebastian Bergmann.

Configuration read from /var/www/jobeet/app/phpunit.xml.dist

.
Time: 0 seconds, Memory: 8.00Mb

OK (1 test, 6 assertions)

アサーションの完全なリストは、 PHPUnit のドキュメントで確認してください。

8.2. 新機能のテストを追加

空の文字列のためのスラグは空の文字列です。それをテストすることはできますし、動作もしますが、URL に空の文字列をいれることは、よい考えではありません。
空の文字列の場合は「n-a」の文字列を返すように slugify() メソッドを変更してみましょう。
先にテストを書いてからメソッドを更新することができ、順番を逆にしてもできます。
それは本当に好みの問題ですが、先にテストを書くことは、コードが計画したものを実際に実装しているという自信を与えてくれます。

src/Ibw/JobeetBundle/Tests/Utils/JobeetTest.php

// ...

$this->assertEquals('n-a', Jobeet::slugify(''));

// ...

現状では、テストを再実行すると、failure が発生します。:

PHPUnit 3.7.22 by Sebastian Bergmann.

Configuration read from /var/www/jobeet/app/phpunit.xml.dist

F

Time: 0 seconds, Memory: 8.25Mb

There was 1 failure:

1) Ibw\JobeetBundle\Tests\Utils\JobeetTest::testSlugify
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'n-a'
+''

/var/www/jobeet/src/Ibw/JobeetBundle/Tests/Utils/JobeetTest.php:13

FAILURES!
Tests: 1, Assertions: 5, Failures: 1.

ここで、Jobeet::slugify メソッドを編集し、先頭に次の条件を追加します。

src/Ibw/JobeetBundle/Utils/Jobeet.php

// ...

    static public function slugify($text)
    {
        if (empty($text)) {
            return 'n-a';
        }

        // ...
    }

このテストは期待どおり通過し、緑のバーを得るでしょう。

8.3. バグによるテスト追加

その後、時間が経過し、ユーザーの1人から、「いくつかのジョブのリンク先が404エラーページになる」という奇妙なバグの報告を受けるとしましょう。
いくらかの調査の後、何かの理由で、これらのジョブが空の会社名、役職、住所 のスラグを持つことを見つけます。​
それはどのような場合に起こりますでしょうか?
データベース内のレコードに目を通すと、カラムは間違いなく空ではありません。
しばらくの間、それについて考え、ビンゴ、原因を見つけます。
文字列が非 ASCII 文字のみで構成されている場合、slugify() メソッドは空の文字列に変換します。
原因を発見したのに満足して、 Jobeet のクラスを編集してすぐに問題を解決しようとするのは、よい考えではありません。
最初に、テストを追加してみましょう。

src/Ibw/JobeetBundle/Tests/Utils/JobeetTest.php

$this->assertEquals('n-a', Jobeet::slugify(' - '));

テストに合格しないことを確認した後、Jobeetのクラスを編集して、空の文字列チェックをメソッドの最後に移動します。

src/Ibw/JobeetBundle/Utils/Jobeet.php

static public function slugify($text)
{
    // ...

    if (empty($text))
    {
        return 'n-a';
    }

    return $text;
}
他のテスト同様に、新しいテストも通りました。 slugify() は、100% のコード網羅率にもかかわらず、バグがありました。
テストを書くときには、すべてのエッジケースを考えることはできません。それは大丈夫です。
しかし、 1 つを発見したときに、コードを修正する前にテストを書く必要があります。
それはコードが時間をかけて良くなることも意味します。それは常に良いことです。

8.4. よりよい slugify メソッドに向けて

おそらく、 Symfony がフランス人によって作られていることを知っているでしょう。
そこで、「アクセント」が含まれているフランス語の単語でテストを追加してみましょう。

src/Ibw/JobeetBundle/Tests/Utils/JobeetTest.php

$this->assertEquals('developpeur-web', Jobeet::slugify('Développeur Web'));
テストは失敗しなければいけません。é を e で置き換える代わりに、slugify() メソッドは、ダッシュ( - ) で置き換えました。
音訳と呼ばれる厳しい問題です。
iconv ライブラリがインストールされている場合は、うまくいけば動くでしょう。
以下で slugify メソッドのコードを置き換えます。

src/Ibw/JobeetBundle/Utils/Jobeet.php

static public function slugify($text)
{
    // replace non letter or digits by -
    $text = preg_replace('#[^\\pL\d]+#u', '-', $text);

    // trim
    $text = trim($text, '-');

    // transliterate
    if (function_exists('iconv'))
    {
        $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
    }

    // lowercase
    $text = strtolower($text);

    // remove unwanted characters
    $text = preg_replace('#[^-\w]+#', '', $text);

    if (empty($text))
    {
        return 'n-a';
    }

    return $text;
}

Symfony のデフォルトのエンコーディングである UTF-8 エンコーディングですべての PHP ファイルを保存することを忘れないでください。 また、 UTF-8 は iconv によって翻訳に使用されます。 また、 iconv が利用可能である場合にのみ、テストファイルを変更します。

src/Ibw/JobeetBundle/Tests/Utils/JobeetTest.php

if (function_exists('iconv')) {
    $this->assertEquals('developpeur-web', Jobeet::slugify('Développeur Web'));
}

8.5. コード網羅率

テストを書くときに、コードの一部を忘れがちです。
新しい機能を追加したり、コード網羅率の統計を確認したい場合に必要があるのは –coverage-HTML オプションを使用してコード網羅率をチェックすることです。
$ phpunit --coverage-html=web/cov/ -c app/

ブラウザで生成されたページ( http://jobeet.local/cov/index.html )を開いて確認してください。

Note

コードカバレッジは XDebug が有効になっており、依存するすべてのものがインストールされている場合にのみ動きます。

$ sudo apt-get install php5-xdebug

cov/index.html は次のようになります。

_images/day-8-code-coverage1.jpg

インジケーターのテストユニットがすべて実施されているということは、すべての行が実施されたという意味で、それだけで、すべてのエッジケースがテストされているわけではないことに注意してください。

8.6. Doctrine の単体テスト

データベース接続を必要とする Doctrine モデルクラスの単体テストは、もう少し複雑です。
すでに開発に使用するデータベースは持っていますが、テスト専用のデータベースを作成することは良い習慣です。
このチュートリアルの初めに、アプリケーションの設定を変更する方法として環境を導入しました。
デフォルトでは、すべての Symfony のテストは test 環境で実行されるので、 test 環境用に異なるデータベースを設定しましょう。
app/config ディレクトリに移動し、 parameters.yml ファイルをコピーして parameters_test.yml を作成します。
parameters_test.yml を編集し、 jobeet_test にデータベースの名前を変更します。
これをインポートするために、 config_test.yml ファイルに追加する必要があります。

app/config/config_test.yml

imports:
    - { resource: config_dev.yml }
    - { resource: parameters_test.yml }
// ...

8.7. Job エンティティのテスト

まず、 Tests/Entity 内に JobTest.php ファイルを作成する必要があります。
setUp 関数は、テストを実行するたびにデータベースを操作します。
最初に、現在のデータベースをドロップし、再作成し、フィクスチャーからデータをロードします。
これは、テストを実行する前に、テスト環境用に作成したデータベースに同じ初期データを持つようにするのに役に立つでしょう。

src/Ibw/JobeetBundle/Tests/Entity/JobTest.php

<?php
namespace Ibw\JobeetBundle\Entity;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Ibw\JobeetBundle\Utils\Jobeet as Jobeet;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Input\ArrayInput;
use Doctrine\Bundle\DoctrineBundle\Command\DropDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\CreateDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\CreateSchemaDoctrineCommand;

class JobTest extends WebTestCase
{
    private $em;
    private $application;

    public function setUp()
    {
        static::$kernel = static::createKernel();
        static::$kernel->boot();

        $this->application = new Application(static::$kernel);

        // drop the database
        $command = new DropDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:drop',
            '--force' => true
        ));
        $command->run($input, new NullOutput());

        // we have to close the connection after dropping the database so we don't get "No database selected" error
        $connection = $this->application->getKernel()->getContainer()->get('doctrine')->getConnection();
        if ($connection->isConnected()) {
            $connection->close();
        }

        // create the database
        $command = new CreateDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:create',
        ));
        $command->run($input, new NullOutput());

        // create schema
        $command = new CreateSchemaDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:schema:create',
        ));
        $command->run($input, new NullOutput());

        // get the Entity Manager
        $this->em = static::$kernel->getContainer()
            ->get('doctrine')
            ->getManager();

        // load fixtures
        $client = static::createClient();
        $loader = new \Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader($client->getContainer());
        $loader->loadFromDirectory(static::$kernel->locateResource('@IbwJobeetBundle/DataFixtures/ORM'));
        $purger = new \Doctrine\Common\DataFixtures\Purger\ORMPurger($this->em);
        $executor = new \Doctrine\Common\DataFixtures\Executor\ORMExecutor($this->em, $purger);
        $executor->execute($loader->getFixtures());
    }

    public function testGetCompanySlug()
    {
        $job = $this->em->createQuery('SELECT j FROM IbwJobeetBundle:Job j ')
            ->setMaxResults(1)
            ->getSingleResult();

        $this->assertEquals($job->getCompanySlug(), Jobeet::slugify($job->getCompany()));
    }

    public function testGetPositionSlug()
    {
        $job = $this->em->createQuery('SELECT j FROM IbwJobeetBundle:Job j ')
            ->setMaxResults(1)
            ->getSingleResult();

        $this->assertEquals($job->getPositionSlug(), Jobeet::slugify($job->getPosition()));
    }

    public function testGetLocationSlug()
    {
        $job = $this->em->createQuery('SELECT j FROM IbwJobeetBundle:Job j ')
            ->setMaxResults(1)
            ->getSingleResult();

        $this->assertEquals($job->getLocationSlug(), Jobeet::slugify($job->getLocation()));
    }

    public function testSetExpiresAtValue()
    {
        $job = new Job();
        $job->setExpiresAtValue();

        $this->assertEquals(time() + 86400 * 30, $job->getExpiresAt()->format('U'));
    }

    protected function tearDown()
    {
        parent::tearDown();
        $this->em->close();
    }
}

8.8. レポジトリクラスのテスト

さて、前の日に作成した関数が正しい値を返すかどうかを確認するために、 JobRepository クラスのいくつかのテストを書いてみましょう。

src/Ibw/JobeetBundle/Tests/Repository/JobRepositoryTest.php

<?php
namespace Ibw\JobeetBundle\Tests\Repository;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Input\ArrayInput;
use Doctrine\Bundle\DoctrineBundle\Command\DropDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\CreateDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\CreateSchemaDoctrineCommand;

class JobRepositoryTest extends WebTestCase
{
    private $em;
    private $application;

    public function setUp()
    {
        static::$kernel = static::createKernel();
        static::$kernel->boot();

        $this->application = new Application(static::$kernel);

        // drop the database
        $command = new DropDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:drop',
            '--force' => true
        ));
        $command->run($input, new NullOutput());

        // we have to close the connection after dropping the database so we don't get "No database selected" error
        $connection = $this->application->getKernel()->getContainer()->get('doctrine')->getConnection();
        if ($connection->isConnected()) {
            $connection->close();
        }

        // create the database
        $command = new CreateDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:create',
        ));
        $command->run($input, new NullOutput());

        // create schema
        $command = new CreateSchemaDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:schema:create',
        ));
        $command->run($input, new NullOutput());

        // get the Entity Manager
        $this->em = static::$kernel->getContainer()
            ->get('doctrine')
            ->getManager();

        // load fixtures
        $client = static::createClient();
        $loader = new \Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader($client->getContainer());
        $loader->loadFromDirectory(static::$kernel->locateResource('@IbwJobeetBundle/DataFixtures/ORM'));
        $purger = new \Doctrine\Common\DataFixtures\Purger\ORMPurger($this->em);
        $executor = new \Doctrine\Common\DataFixtures\Executor\ORMExecutor($this->em, $purger);
        $executor->execute($loader->getFixtures());
    }

    public function testCountActiveJobs()
    {
        $query = $this->em->createQuery('SELECT c FROM IbwJobeetBundle:Category c');
        $categories = $query->getResult();

        foreach($categories as $category) {
            $query = $this->em->createQuery('SELECT COUNT(j.id) FROM IbwJobeetBundle:Job j WHERE j.category = :category AND j.expires_at > :date');
            $query->setParameter('category', $category->getId());
            $query->setParameter('date', date('Y-m-d H:i:s', time()));
            $jobs_db = $query->getSingleScalarResult();

            $jobs_rep = $this->em->getRepository('IbwJobeetBundle:Job')->countActiveJobs($category->getId());
            // This test will verify if the value returned by the countActiveJobs() function
            // coincides with the number of active jobs for a given category from the database
            $this->assertEquals($jobs_rep, $jobs_db);
        }
    }

    public function testGetActiveJobs()
    {
        $query = $this->em->createQuery('SELECT c from IbwJobeetBundle:Category c');
        $categories = $query->getResult();

        foreach ($categories as $category) {
            $query = $this->em->createQuery('SELECT COUNT(j.id) from IbwJobeetBundle:Job j WHERE j.expires_at > :date AND j.category = :category');
            $query->setParameter('date', date('Y-m-d H:i:s', time()));
            $query->setParameter('category', $category->getId());
            $jobs_db = $query->getSingleScalarResult();

            $jobs_rep = $this->em->getRepository('IbwJobeetBundle:Job')->getActiveJobs($category->getId(), null, null);
            // This test tells if the number of active jobs for a given category from
            // the database is the same as the value returned by the function
            $this->assertEquals($jobs_db, count($jobs_rep));
        }
    }

    public function testGetActiveJob()
    {
        $query = $this->em->createQuery('SELECT j FROM IbwJobeetBundle:Job j WHERE j.expires_at > :date');
        $query->setParameter('date', date('Y-m-d H:i:s', time()));
        $query->setMaxResults(1);
        $job_db = $query->getSingleResult();

        $job_rep = $this->em->getRepository('IbwJobeetBundle:Job')->getActiveJob($job_db->getId());
        // If the job is active, the getActiveJob() method should return a non-null value
        $this->assertNotNull($job_rep);

        $query = $this->em->createQuery('SELECT j FROM IbwJobeetBundle:Job j WHERE j.expires_at < :date');         $query->setParameter('date', date('Y-m-d H:i:s', time()));
        $query->setMaxResults(1);
        $job_expired = $query->getSingleResult();

        $job_rep = $this->em->getRepository('IbwJobeetBundle:Job')->getActiveJob($job_expired->getId());
        // If the job is expired, the getActiveJob() method should return a null value
        $this->assertNull($job_rep);
    }

    protected function tearDown()
    {
        parent::tearDown();
        $this->em->close();
    }
}

CategoryRepository クラスに同じことを行います。

src/Ibw/JobeetBundle/Tests/Repository/CategoryRepositoryTest.php

<?php
namespace Ibw\JobeetBundle\Tests\Repository;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Input\ArrayInput;
use Doctrine\Bundle\DoctrineBundle\Command\DropDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\CreateDatabaseDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\CreateSchemaDoctrineCommand;

class CategoryRepositoryTest extends WebTestCase
{
    private $em;
    private $application;

    public function setUp()
    {
        static::$kernel = static::createKernel();
        static::$kernel->boot();

        $this->application = new Application(static::$kernel);

        // drop the database
        $command = new DropDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:drop',
            '--force' => true
        ));
        $command->run($input, new NullOutput());

        // we have to close the connection after dropping the database so we don't get "No database selected" error
        $connection = $this->application->getKernel()->getContainer()->get('doctrine')->getConnection();
        if ($connection->isConnected()) {
            $connection->close();
        }

        // create the database
        $command = new CreateDatabaseDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:database:create',
        ));
        $command->run($input, new NullOutput());

        // create schema
        $command = new CreateSchemaDoctrineCommand();
        $this->application->add($command);
        $input = new ArrayInput(array(
            'command' => 'doctrine:schema:create',
        ));
        $command->run($input, new NullOutput());

        // get the Entity Manager
        $this->em = static::$kernel->getContainer()
            ->get('doctrine')
            ->getManager();

        // load fixtures
        $client = static::createClient();
        $loader = new \Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader($client->getContainer());
        $loader->loadFromDirectory(static::$kernel->locateResource('@IbwJobeetBundle/DataFixtures/ORM'));
        $purger = new \Doctrine\Common\DataFixtures\Purger\ORMPurger($this->em);
        $executor = new \Doctrine\Common\DataFixtures\Executor\ORMExecutor($this->em, $purger);
        $executor->execute($loader->getFixtures());
    }

    public function testGetWithJobs()
    {
        $query = $this->em->createQuery('SELECT c FROM IbwJobeetBundle:Category c LEFT JOIN c.jobs j WHERE j.expires_at > :date');
        $query->setParameter('date', date('Y-m-d H:i:s', time()));
        $categories_db = $query->getResult();

        $categories_rep = $this->em->getRepository('IbwJobeetBundle:Category')->getWithJobs();
        // This test verifies if the number of categories having active jobs, returned
        // by the getWithJobs() function equals the number of categories having active jobs from database
        $this->assertEquals(count($categories_rep), count($categories_db));
    }

    protected function tearDown()
    {
        parent::tearDown();
        $this->em->close();
    }
}

テストを書き終えた後、全体の機能のコード網羅率を生成するため、次のコマンドを実行します。

$ phpunit --coverage-html=web/cov/ -c app src/Ibw/JobeetBundle/Tests/Repository/

ブラウザでページ( http://jobeet.local/cov/Repository.html )を開くと、リポジトリのテストのコードカバレッジが100% 完了になっていないことがわかります。

_images/Day-8-coverage-not-complete.jpg
それでは、100% のコード網羅率を達成するために JobRepository ためのいくつかのテストを追加してみましょう。
今のところ、データベースにはアクティブなジョブを持たない二つのカテゴリと、一つだけアクティブなジョブを持つ一つのカテゴリを持ちます。
それは、 $max と $offset パラメータをテストする際に、最低でも 3 つのアクティブなジョブを持つカテゴリにおいて、下記のテストを実行するためです。
そのために、 testGetActiveJobs() にて、 foreach 文の内部にこれを追加します。

src/Ibw/JobeetBundle/Tests/Repository/JobRepositoryTest.php

// ...
foreach ($categories as $category) {
    // ...

    // 少なくとも3つのアクティブなジョブが選択したカテゴリにはあり、
    // getActiveJobs() メソッドを limit と offset パラメーターを利用してテストし、
    // 100% のコード網羅率にします。
    // If there are at least 3 active jobs in the selected category, we will
    // test the getActiveJobs() method using the limit and offset parameters too
    // to get 100% code coverage
    if($jobs_db > 2 ) {
        $jobs_rep = $this->em->getRepository('IbwJobeetBundle:Job')->getActiveJobs($category->getId(), 2);
        // This test tells if the number of returned active jobs is the one $max parameter requires
        $this->assertEquals(2, count($jobs_rep));

        $jobs_rep = $this->em->getRepository('IbwJobeetBundle:Job')->getActiveJobs($category->getId(), 2, 1);
        // We set the limit to 2 results, starting from the second job and test if the result is as expected
        $this->assertEquals(2, count($jobs_rep));
    }
}
// ...

再びコードカバレッジコマンドを実行します。

$ phpunit --coverage-html=web/cov/ -c app src/Ibw/JobeetBundle/Tests/Repository/

ここで、コード網羅率を確認するすると、 100% が表示されます。

_images/Day-8-coverage-complete.jpg

これで今日はすべてです!明日は、機能テストについてお話します。

See also

Symfony2日本語ドキュメント

豊富な日本語ドキュメントがありますので合わせて読み進めてみましょう。

Note

Creative Commons License

このチュートリアルは、クリエイティブ・コモンズ・ライセンス 表示 - 継承 3.0 非移植 (CC BY-SA 3.0) のもとでライセンスされています。 翻訳の元にしたオリジナルはこちらです。 Symfony2 Jobeet http://www.intelligentbee.com/blog/tag/symfony2-jobeet/.