43

I am quite new to the world of testing and I want to make sure I am on the right track.

I am trying to setup unit tests in a symfony2 project using phpunit.

PHPUnit is working and the simple default controller tests work fine. (Yet this is not about functional testing but unit testing my application.)

My project relies heavily on database interactions though, and as far as I understand from phpunit's documentation, I should set up a class based on \PHPUnit_Extensions_Database_TestCase, then create fixtures for my db and work from there.

Yet, symfony2 only offers a WebTestCase class which only extends from \PHPUnit_Framework_TestCase out of the box.

So am I right to assume that I should create my own DataBaseTestCase which mostly copies WebTestCase, only difference being that it extends from \PHPUnit_Extensions_Database_TestCase and implements all its abstract methods?

Or is there another "built-in" recommended workflow for symfony2 concerning database-centric tests?

As I want to make sure that my models store and retrieve the right data, I do not want to end up testing the specifics of doctrine by accident.

4

3 に答える 3

35

PHPUnit_Extensions_Database_TestCase主に次の 2 つの理由により、 を使用したことがありません。

  • うまくスケーリングしません。単一のテストごとにデータベースをセットアップして破棄し、データベースに大きく依存するアプリケーションがある場合、同じスキーマを何度も作成して削除することになります。
  • テスト内だけでなく、開発データベース内にもフィクスチャを配置するのが好きで、一部のフィクスチャは本番環境でも必要です (最初の管理者ユーザーまたは製品カテゴリなど)。それらをphpunitにのみ使用できるxml内に置くことは、私には正しくないようです。

理論的には私のやり方...

私はフィクスチャにdoctrine/doctrine-fixtures-bundleを使用し (目的が何であれ)、すべてのフィクスチャでデータベース全体をセットアップします。次に、このデータベースに対してすべてのテストを実行し、テストによってデータベースが変更された場合は、必ずデータベースを再作成します。

利点は、テストが読み取りのみで何も変更しない場合、データベースを再度セットアップする必要がないことです。変更の場合は、ドロップして再度作成するか、変更を元に戻す必要があります。

データベースをセットアップし、sqlite ファイルをコピーしてクリーンなファイルに置き換え、元のデータベースに戻すことができるため、テストには sqlite を使用します。そうすれば、データベースをドロップして作成し、クリーンなデータベースのためにすべてのフィクスチャを再度ロードする必要がなくなります。

...そしてコードで

symfony2 と phpunit でデータベース テストを行う方法についての記事を書きました。

sqlite を使用していますが、MySQL や Postgres などを使用するように簡単に変更できると思います。

さらに考える

うまくいく可能性のある他のアイデアを次に示します。

  • データベースを使用する前に (setUp メソッド内で) トランザクションを開始し、tearDown を使用してロールバックするテスト セットアップについて読んだことがあります。そうすれば、データベースを再度セットアップする必要はなく、一度初期化するだけで済みます。
  • 上記の私のセットアップには、データベースとの対話なしでいくつかの単体テストを実行するだけであっても、phpunit が実行されるたびにデータベースがセットアップされるという欠点があります。データベースがセットアップされているかどうかを示すグローバル変数を使用し、テスト内でこの変数をチェックし、まだ発生していない場合はデータベースを初期化するメソッドを呼び出すセットアップを試しています。そうすれば、テストでデータベースが必要な場合にのみ、セットアップが行われます。
  • sqlite の問題の 1 つは、まれに MySQL と同じように動作しないことです。MySQL と sqlite で動作が異なり、MySQL ですべてが機能しているときにテストが失敗するという問題がありました。それが何だったのか正確には思い出せません。
于 2012-09-20T08:34:20.017 に答える
-1

このクラスを使用できます:

<?php

namespace Project\Bundle\Tests;

require_once dirname(__DIR__).'/../../../app/AppKernel.php';

use Doctrine\ORM\Tools\SchemaTool;

abstract class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* @var Symfony\Component\HttpKernel\AppKernel
*/
protected $kernel;

/**
 * @var Doctrine\ORM\EntityManager
 */
protected $entityManager;

/**
 * @var Symfony\Component\DependencyInjection\Container
 */
protected $container;


public function setUp()
{
    // Boot the AppKernel in the test environment and with the debug.
    $this->kernel = new \AppKernel('test', true);
    $this->kernel->boot();

    // Store the container and the entity manager in test case properties
    $this->container = $this->kernel->getContainer();
    $this->entityManager = $this->container->get('doctrine')->getEntityManager();

    // Build the schema for sqlite
    $this->generateSchema();


    parent::setUp();
}

public function tearDown()
{
    // Shutdown the kernel.
    $this->kernel->shutdown();

    parent::tearDown();
}

protected function generateSchema()
{
    // Get the metadatas of the application to create the schema.
    $metadatas = $this->getMetadatas();

    if ( ! empty($metadatas)) {
        // Create SchemaTool
        $tool = new SchemaTool($this->entityManager);
        $tool->createSchema($metadatas);
    } else {
        throw new Doctrine\DBAL\Schema\SchemaException('No Metadata Classes to process.');
    }
}

/**
 * Overwrite this method to get specific metadatas.
 *
 * @return Array
 */
protected function getMetadatas()
{
    return $this->entityManager->getMetadataFactory()->getAllMetadata();
}
}

そして、エンティティをテストできます。このようなもの(エンティティ User があると仮定)

//Entity Test
class EntityTest extends TestCase {

    protected $user;

    public function setUp()
    {
         parent::setUp();
         $this->user = new User();
         $this->user->setUsername('username');
         $this->user->setPassword('p4ssw0rd');


         $this->entityManager->persist($this->user);
         $this->entityManager->flush();

    }

    public function testUser(){

         $this->assertEquals($this->user->getUserName(), "username");
         ...

    }

}

この助けを願っています。

ソース: theodo.fr/blog/2011/09/symfony2-unit-database-tests

于 2012-05-28T16:12:55.283 に答える