データを取り扱う
テストはお互いに影響を及ぼし合ってはなりません。これが大雑把なルールです。 テストがデータベースとやり取りする際に内部のデータを変更しかねないため、最終的にデータの不一致や矛盾を生じさせるかもしれないのです。テストはすでに挿入されているレコードを挿入したり、削除されているレコードを検索しようとするかもしれません。テストの失敗を回避するため、データベースは各テストを行う前に初期状態になっていなければなりません。Codeceptionには、データをクリーンにするための方法やアプローチがいくつか存在します。
この章では、前章のクリーンアップに関する注意を要約するとともに、データストレージバックエンドを選択する方法の最善策について提案します。
私たちがデータベースをクリーンアップすると決めた時、私たちはそれをできるだけ速く行うべきです。テストは常に速く実行される必要があります。データベースを一から再構築するのは最良の方法とは言えないかもしれませんが、唯一の方法とも言えるかもしれません。いずれにせよ、テストのためだけに特別なデータベースを使用してください。絶対に開発環境または本番環境のデータベースでテストを実行しないでください!
自動クリーンアップ
Codeceptionにはデータベースと対話をする際に必要なほとんどのタスクを行ってくれるDbモジュールがあります。デフォルトでは、dumpからデータベースを再構築し、各テストが終了した後にクリーンアップを試みます。このモジュールのデータベースのdumpはSQLフォーマットです。codeception.yml内ですでに設定が準備されています。
modules:
config:
Db:
dsn: 'PDO DSN HERE'
user: 'root'
password:
dump: tests/_data/your-dump-name.sql
あなたのテストスイートでこのモジュールを有効化したら、自動的にdumpからデータベースにデータが挿入され、各テストの実行時に再構築されます。これらの設定はpopulateとcleanupオプションの変更によってfalseに設定することができます。
Dbモジュールはラフなツールです。PDOでサポートされているどのデータベースでも動作します。もし速度が遅くなければ、すべてのテストで使用できます。dumpをロードするのはとても時間がかかりますが、他の手段を使うこともできます。機能テストや単体テストを行う際などにアプリケーションとテストがデータベース接続を共有している時、速度を向上させる最善策はすべてのコードをトランザクションに設置し、テスト終了時にロールバックすることです。
分離された接続
受け入れテストでは、異なるデータベース接続が使用されているため、テスト速度を向上するにはSQLiteファイルのデータベースを使うことができます。また、代替案として、各テストごとにデータベースを作成するのを避け、テスト終了後にすべてのアップデートをクリーンアップすることも考えられます。Dbモジュールはあなたのアプリケーションと同等の機能を提供しており、アサーション(seeInDatabaseアクション)のためにデータベースにアクセスしたり、自動クリーンアップしたりします。
共有された接続
あなたのアプリケーションもしくはその一部がCodeceptionプロセス内で実行されている場合、アプリケーション接続をテストで使用することが可能です。接続にアクセスできれば、すべてのデータベース操作はグローバルトランザクションに含むことができ、最後にロールバックされます。それは劇的にパフォーマンスを改善するでしょう。最後にデータベースに何も書かれないため、実際にデータベースの再構築が必要とならないのです。
ORMモジュール
アプリケーションがDoctrineやDoctrine2のようなORMを使用しているのでしたら、各モジュールでスイートに接続してください。デフォルトでは、トランザクション内のすべてをカバーします。もしあなたが複数のデータベース接続を使っていない、もしくはORMによって追跡されないトランザクションである場合、このモジュールはあなたの役には立たないでしょう。
ORMモジュールはDbモジュールと接続できますが、デフォルトでは両方ともクリーンアップを行います。従って、あなたが明示的に使用しているモジュールを設定する必要があります。
tests/functional.suite.ymlは次のようになります。
modules:
enabled:
- Db:
cleanup: false
- Doctrine2:
depends: Symfony2
- \Helper\Functional
この場合でも、Dbモジュールはテスト後にdumpからデータベースの再構築を行います。populate: falseを使って、それを無効にしてください。
Dbhモジュール
PostgreSQLまたは他のネストされたトランザクションをサポートしているデータベースを使っているのでしたら、Dbhモジュールを使用してください。アプリケーションからPDOインスタンスを取得し、テストの開始でトランザクションを開始して終了後にロールバックします。PDO接続はブートストラップファイルで定義することができます。このモジュールはDbモジュールのseeInDatabaseメソッドとdontSeeInDatabaseメソッドを上書きします。
再構築にDbモジュールを使用し、クリーンアップにDhpモジュールを行うには、次のように設定してください。
modules:
enabled:
- Db:
cleanup: false
- Dbh
- \Helper\Functional
DbhモジュールはDbモジュールの後に来なければいけないことに注意してください。これによってDbhモジュールはアクションを上書きできるようになります。
フィクスチャ
フィクスチャはテストで使用できるサンプルデータです。このデータは生成されるか、サンプルデータベースから取得されます。フィクスチャは別のPHPファイルで定義され、テストにロードできます。
受け入れテストと機能テストのフィクスチャ
tests/functional内にfixtures.phpファイルを作り、テストで使用するデータをデータベースからロードしてみましょう。
<?php
// サンプルデータベースからユーザーを取得します
// Dbモジュールを使用します
$john = User::findOneBy('name', 'john');
?>
受け入れテストと機能テストのサンプルでのフィクスチャの使用方法です:
<?php
require 'fixtures.php';
$I = new FunctionalTester($scenario);
$I->amLoggedAs($john);
$I->see('Welcome, John');
?>
また、Fakerライブラリーを使ってブートストラップファイル内にテストデータを作成することもできます。
テストごとのフィクスチャ
もしあなたが1つのテストに対して特別なデータベースレコードを作りたいのなら、DbモジュールのhaveInDatabaseメソッドを使用できます。
<?php
$I = new FunctionalTester($scenario);
$I->haveInDatabase('posts', [
'title' => 'Top 10 Testing Frameworks',
'body' => '1. Codeception'
]);
$I->amOnPage('/posts');
$I->see('Top 10 Testing Frameworks');
?>
haveInDatabaseは、与えられた値の行を新しくデータベースに挿入します。追加されたレコードはすべてテスト終了後に削除されます。似たようにMongoDBモジュールでは、haveInCollectionメソッドが存在します。
まとめ
Codeceptionは、データを取り扱う開発者を見捨てたりしません。データベースを構築したりクリーンアップするためのツールはDbモジュール内にバンドルされています。テストでサンプルデータを操作するには、ブートストラップファイル内で定義されるフィクスチャを使用してください。