[〜#〜] hsqldb [〜#〜] は素晴らしいです。また、組み込みモード(専用サーバーは不要)を備えているため、Proof of Conceptsなどの迅速なプロトタイピングが可能になり、さまざまなデータをすばやく簡単に保存できるため、本番環境ですぐに使用できるアプリケーションにも最適です。
ただし、私が過去数年間取り組んだプロジェクトの少なくとも90%は、SQLデータベースを何らかの方法で処理する場合、組み込みHSQLDBを使用するユニットテストをやむを得ず行うことになります。
確かに、これらのプロジェクト(ほとんどの場合、標準のMaven構造を使用します)には、大量の「単体テスト」(または少なくとも、ある種のテストがありますが、「単体テスト」領域にあります)があります。いくつかのCRUD操作を実行して結果を確認するために、HSQLDBの1つ以上の埋め込みインスタンスを使用するプロジェクト(「src/test/Java」など)の)。
私の質問は、これはアンチパターンですか? HSQLDBは統合が簡単で、組み込みサーバーは非常に軽量であるという事実は、実際のデータベースの「モックアップ」として見過ごされがちな場合に見落とされる可能性があるということですか?このようなテストは、統合テストのように扱うべきではありません(各テストは「何か」[〜#〜]と[〜#〜]データベースサーバーとの「何か」の統合))または、「単体テスト」定義に何か不足していますか?そして、このようにHSQLDBを使用することは、「単体テスト」定義の「依存関係を模擬し、単体のみをテストする」部分に固執すると言うことができますか?
DAOをテストするときは、データ層に触れるときに記述するコードの品質を保証するために必要なステップとして、HSQLDB(またはDBUnit)のようなものを使用することを検討します。すでに指摘したように、これは防弾ソリューションではありませんが、方言と組み合わせると、ケースの妥当な部分をカバーできます。
私の唯一のポイントは次のとおりです。nit-testsについて話すときは注意しましょう。 私の制御外のような外部コンポーネントと対話するクラスをテストするとき(つまり、非決定的な動作を生成する可能性があります)、それを自動的に統合テストと見なします。
インターフェースによって隠された具象クラスで(JDBCドライバー、ORMなどを介して)データストアと直接やり取りするロジックを除外したと仮定すると、DAOに適切な単体テストを渡すことで、DAOの適切なユニットテストが開発されます。テストする既知の値のセットを返すインターフェースの具体的なモック実装。
IMO:
私はいくつかの本当に悪い問題を見つけて修正し、HSQLデータベースに対してテストすることで開発を大幅にスピードアップしました。最下位レベルのアダプタークラス(つまり、DAO)は、実際のラウンドトリップからライブデータベースへの分離が困難な場合があるため、単体テストでテストされないことがあります。私は過去にConnectionとJDBCアーティファクトをあざけたことがありますが、実際には、インメモリデータベースに対してテストするよりもはるかに困難でした。
あるプロジェクトでは、HSQLに対して開発とテストを行い、MySqlに対してローカルで実行し、SQL-Serverに対して本番環境にデプロイしました。驚くべきことに、それはうまくいきました。私が遭遇した最大の統合問題は、私自身の仕様の誤解によるものでした(秒vsミリ秒、笑)。
永続化フレームワークは(Hibernateが行うように)基礎となるデータベースをマスクできますが、永続化フレームワーク自体が十分に複雑なセマンティクスを追加する可能性があるため、それを単独で実行すると、本格的な統合テストに到達する前に多くの癖を取り除くことができます。
HibernateまたはJPAを使用して、多数の結合を持つ複雑な結果セットを構築する場合を考えてみます。厄介で何度も試してみる場合は、ライブデータベースに対して開発およびテストできます。ただし、オーバーヘッドを少なくして、インメモリデータベースに対して開発およびテストすることもできます。また、データベースフィクスチャのセットアップ/ティアダウンスクリプトや、テストとビルドを他の人と調整することについて心配する必要もありません。また、インメモリデータベースに対してテストする場合は、他の単体テストと同様に、これらのテストをリグレッション用に利用できるというメリットがあります。
単体テスト以上のテストが「単独で行われる」という「コンポーネントテスト」という言葉を聞いたことがあります。
単体テスト、コンポーネントテスト(実際の名前の場合)、および統合テストはすべて価値を提供します。チームはお互いを省くことができます(そうです、多くのチームは単体テストを行わず、統合テストのみに依存しています)が、それを行うと、他のテスト階層がもたらす利点を失うことになります。
メモリに統合することで分離されたテストの場合、利点はコードの迅速な検証と、その後の高速回帰です。分離されたテストの利点であり、追加のインストール、ライセンス、ハードウェアは必要ありません。これにより、データベースがプロビジョニングされるまでDAOをテストするだけの場合よりも、より多くのレベルのコードを分離して検証できます。
したがって、実用的な価値があります。必須ではありませんが、やり終えたときは、満足するよりも満足するようになりました。
実稼働環境で使用しているのと同じデータベースを(単体)テストに使用します。
その理由は簡単です。データベースの動作が異なるからです。各データベースには独自の独自機能があります。データベースアクセスにORMレイヤーを使用する場合でも、データベースの動作は異なり、パフォーマンスも向上します。
もちろん、単体テスト用の組み込みデータベースの利点は、何も構成する必要がないことです。しかし、すべての開発者のマシンにデータベースをインストールし、単体テストに使用するように構成することはそれほど難しくありません。
先ほどのプロジェクトでも同じ状況でした。 JDBCを使用して、データベースでSQLステートメントを実行しました。アプリケーションのテストを作成することを決定したとき、組み込みデータベースを使用しました。そのため、単体テストでは一部のバグを再現できず、組み込みデータベースが本番データベースの機能をサポートしていないため、アプリケーションの一部をテストできない状況が発生しました。したがって、すべての開発者がテスト環境を実行するためにPCの運用環境でも使用したものと同じデータベースをインストールしました。
私は過去にそのようなアプローチを使用していますが、これが「アンチパターン」であるかどうかはわかりません(一部の人々は彼の個人的な感情や経験を普遍的なルールに引き上げようとしますが、そうではありません)。
単体テストの場合、実際の単体テストでは、インメモリデータベースなどの外部のものは使用しません(hashMapまたはスタブライブラリを使用したスタブと比較すると、それほど軽量ではありません)。データアクセスにDIおよびリポジトリやDAOなどの単純なパターンを使用する場合、これは非常に簡単に実現できます。私の目的は、非常に迅速に実行される多くの単体テストを作成することです。迅速に、1分未満で3Kテストを考えています。
統合テストでは、このテストで実際のデータストレージソフトウェアを使用することを好みます。このテストの目的は、私のソフトウェアと実際のデータストレージ間の統合を証明することです。ここで別のデータストレージを使用すると、この意図が崩れます。テスト。私はこの統合を実証するためにできる限り少ない統合テストを書くようにしています、そして通常このテストは通常のビルドの外で実行されます(例えば夜間ビルドでのみ)
私は時々HSQLDBを使用してシンプルなデモや概念実証を構築します。これは優れたツールですが、通常の開発ワークフローでこのツールがどこにあるのかもうわかりません。
MyBatisのようなユニットテストデータアクセス製品の場合、埋め込みHSQLDBを使用したテストは完全に適切だと思います(少なくともMyBatisでは、このためにHSQLDBを使用していることはわかっています)。
他のほとんどのプロジェクトでは、私はこのやり過ぎを検討します。実際のデータベースにアクセスする簡単な統合テスト(これらは他のテストに影響を与える可能性のあるテスト)を作成し、各クエリ/ステートメントが少なくとも1回使用されることを確認します。プロジェクトの統合テストは単体テストよりもはるかに少ないはずです。
単体テストでは、DAOまたはDBにアクセスするもの(「アダプター」)のモックを作成します。