データベースに緊密に結合されたアプリケーションに統合されるモデルの単体テストでの最良のアプローチは何でしょうか?
ここでの特定のシナリオはショッピングカートです-カートからのアイテムの追加と削除、および価格設定ロジックなどをテストできるようにしたいと思います。データベースへのアクセスは避けてください。
データベースに緊密に結合されたアプリケーションに統合されるモデルの単体テストでの最良のアプローチは何でしょうか?
ここでの特定のシナリオはショッピングカートです-カートからのアイテムの追加と削除、および価格設定ロジックなどをテストできるようにしたいと思います。データベースへのアクセスは避けてください。
回答:
モデルは(具体的な)DBに依存するべきではありません。モデルに渡される抽象DB(「インターフェイス」と呼ばれる)のみを知っている場合は、DBをモックオブジェクトに置き換えることができます。
では、オブジェクト指向プログラミング、モックオブジェクトは、制御の方法で、実際のオブジェクトの動作を模倣するオブジェクトをシミュレートしています。プログラマーは通常、モックオブジェクトを作成して他のオブジェクトの動作をテストします。これは、自動車の設計者が衝突テストダミーを使用して、車両の衝撃における人間の動的な動作をシミュレートするのとほぼ同じ方法で...
「最良」は主観的ですが、テストデータベース接続を使用するだけでかまいません。
フィクスチャを使用していくつかのテストデータ(購入するサンプル製品)をロードし、テストするクラス/関数のテストケースを記述します。
私は、構築されたsymfonyの1.4(PHP)のためのプラグインを(特に)この問題に取り組むために。これは、Djangoのテストフレームワーク(Python)の動作方法をモデルにしています。フレームワークは、各テストが開始する前に個別のテストデータベースを構築および設定し、各テストの完了後にテストデータベースを破棄します。
パフォーマンス(スキーマが変更されない場合、構造全体を再構築するのではなく、単にデータをクリアしないのはなぜか)と利便性(データベースの検査後にテストが失敗したので、無差別に破壊しないでください!)、私は少し異なるアプローチを取りました。
最初のテストが実行される前に、最後のテスト以降にモデルが変更された場合に備えて、データベースが破棄されて再構築されます。後続の各テストを実行する前に、データベース内のデータは消去されますが、構造は再構築されません(必要に応じてテストから手動で再構築をトリガーできます)。
各テストでデータフィクスチャを選択的にロードすることにより、後続のテストを妨げることなく、そのテストに適した環境を作成できます。フィクスチャファイルを再利用することもできます。これにより、このタスクの煩わしさが大幅に軽減されます(ただし、テストの作成で最も嫌いな部分です!)。
どちらのテストフレームワークでも、データベースアダプタは、「実稼働」接続ではなくテスト接続を使用して、テスト実行による既存データの破損を防止するように構成されています。
先に進み、フィクスチャを使用してデータをプリロードしてください。それは、データの操作をテストするときに、単体テストフレームワークが一般的に機能するように見える方法です。
しかし、あらゆる種類のデータベースに接続する必要がなく、ユニットテストがコードの外部に触れないという非常に厳格な定義に従うことを本当に避けたい場合は、オブジェクトのモックを見てください-それはあなたにアイデアを与えるかもしれません。
たとえば、必要なコードにSQLを直接ドロップする代わりに、そのSQLの機能のみを実行するメソッドを呼び出す方法があります。使用するPerson.getPhoneNumber()
のではなく、例えば、SELECT phone_number FROM person WHERE id = <foo>
。一見簡潔でわかりやすいだけでなく、テスト中にPersonオブジェクトをモックすることで、データベースにアクセスする代わりに、getPhoneNumber()
常に555-555-5555
何かを返すことができます。
少し長く巻かれていれば、junitでこれを行うのはかなり簡単です。
「セットアップ」は、一時テーブルのセットを定義および設定する必要があります。
その後、すべての更新、挿入、削除機能の単体テストを実行できます。
各テストについて、更新メソッドを呼び出してから、いくつかのSQLを実行して期待される結果を確認します。
「分解」フェーズでは、すべてのテーブルをドロップします。
この方法では、常に同じ初期データに対して同じテストを実行します。テスト間でテーブルを保持すると、失敗したテストによって「汚染」されてしまいます。また、すべてのテストで新しいキーを発明し続ける必要があるため、一貫した「挿入」テストはほとんど不可能です。