61

この質問は、多かれ少なかれプログラミング言語に依存しません。しかし、私は最近 Java に夢中になっているので、そこから例を引き出します。OOP のケースについても考えているので、メソッドをテストする場合は、そのメソッド クラスのインスタンスが必要です。

単体テストコア ルールは、自律的であるべきであり、依存関係からクラスを分離することで達成できるということです。それにはいくつかの方法があり、 IoCを使用して依存関係を注入するかどうか(Java の世界では、注入機能を提供する Spring、EJB3 およびその他のフレームワーク/プラットフォームがあります) および/またはオブジェクトをモックするかどうか (Java の場合は、JMockおよびEasyMock ) を使用して、テスト対象のクラスをその依存関係から分離します。

異なるクラス*でメソッドのグループをテストする必要があり、それらが適切に統合されていることを確認する必要がある場合は、統合テストを作成します。そして、ここに私の質問があります!

  • 少なくとも Web アプリケーションでは、多くの場合、状態はデータベースに永続化されます。単体テストと同じツールを使用して、データベースからの独立性を実現できます。しかし、私の謙虚な意見では、統合テストにデータベースを使用しないことがあまりにも嘲笑されている場合があると思います (ただし、異議を唱えることは自由です。データベースをまったく使用しないことは、質問を無関係にするため、有効な答えでもあります)。 )。
  • 統合テストにデータベースを使用する場合、そのデータベースにどのようにデータを入力しますか? 私は2つのアプローチを見ることができます:
    • 統合テスト用のデータベース コンテンツを保存し、テストを開始する前にロードします。それが SQL ダンプ、データベース ファイル、XML などとして保存されている場合、興味深い情報が得られます。
    • API 呼び出しによって必要なデータベース構造を作成します。これらの呼び出しは、おそらくテスト コード内でいくつかのメソッドに分割され、これらのメソッドのそれぞれ失敗する可能性があります。統合テストが他のテストに依存していると見なされる可能性があります。

テストに必要なデータベース データが必要なときに確実に存在するようにするにはどうすればよいですか? また、なぜその方法を選んだのですか?

興味深い部分は動機にあるので、動機とともに答えてください。「それがベストプラクティスです!」と言っているだけであることを忘れないでください。本当の動機ではなく、読んだり誰かから聞いたりしたことを繰り返しているだけです。その場合、それがベストプラクティスである理由を説明してください。

*技術的に正しくない可能性がありますが、単体テストの定義に、同じクラスの (同じまたは他の) インスタンスで他のメソッドを呼び出す 1 つのメソッドを含めています。お気軽に訂正してください。

4

9 に答える 9

55

API 呼び出しを使用してテスト データを作成することを好みます。

テストの開始時に、空のデータベース (インメモリまたは本番環境で使用されるものと同じもの) を作成し、インストール スクリプトを実行してそれを初期化し、データベースで使用されるテスト データを作成します。テスト データの作成は、たとえばオブジェクト マザーパターンを使用して編成することができます。これにより、同じデータを多くのテストで再利用できます。

副作用のない再現可能なテストを行うために、すべてのテストの前にデータベースを既知の状態にする必要があります。そのため、テストが終了したら、テスト データベースを削除するか、トランザクションをロールバックして、前のテストが成功したか失敗したかに関係なく、次のテストで常に同じ方法でテスト データを再作成できるようにする必要があります。

データベース ダンプ (または類似のもの) のインポートを避ける理由は、テスト データをデータベース スキーマと結び付けるためです。データベース スキーマが変更されると、テスト データも変更または再作成する必要があり、手作業が必要になる場合があります。

テスト データがコードで指定されている場合は、IDE のリファクタリング ツールをすぐに利用できます。データベース スキーマに影響する変更を行うと、おそらく API 呼び出しにも影響するため、とにかく API を使用してコードをリファクタリングする必要があります。ほぼ同じ労力で、テスト データの作成をリファクタリングすることもできます。特にリファクタリングを自動化できる場合 (名前の変更、パラメーターの導入など)。ただし、テストがデータベース ダンプに依存している場合は、API を使用するコードのリファクタリングに加えて、データベース ダンプを手動でリファクタリングする必要があります。

データベースの統合テストに関連するもう 1 つのことは、以前のデータベース スキーマからのアップグレードが正しく機能することをテストすることです。そのためには、本Refactoring Databases: Evolutionary Database Designまたはこの記事を読むことをお勧めします: http://martinfowler.com/articles/evodb.html

于 2009-02-12T19:13:18.597 に答える
5

これらの2つのアプローチが排他的であると定義されているのはなぜですか?

  • 既存のデータセット、特に過去に問題を引き起こした特定のデータを使用 しないことについての実行可能な議論は見当たり ません。

  • 問題を引き起こすと想像できるすべての可能な条件でそのデータをプログラムで拡張しないこと、さらには統合テスト用のランダムなデータを少しでも拡張しないことについて、実行可能な議論は見当たりません。

最新のアジャイルアプローチでは、ユニットテストは毎回同じテストを実行することが非常に重要です。これは、単体テストがバグを見つけることではなく、開発時にアプリの機能を維持し、開発者が必要に応じてリファクタリングできるようにすることを目的としているためです。

一方、統合テストは、予期しないバグを見つけるように設計されています。私の意見では、毎回いくつかの異なるデータを実行することも良いことです。失敗した場合でも、テストで失敗したデータが保持されることを確認する必要があります。正式な統合テストでは、バグ修正を除いてアプリケーション自体がフリーズするため、テストを変更して、可能な限り多くのバグと種類のバグをテストできることを忘れないでください。統合では、アプリで台所の流し台を投げることができ、投げるべきです。

もちろん、他の人が指摘しているように、これは当然、開発しているアプリケーションの種類や所属している組織の種類などによって異なります。

于 2009-02-16T05:51:49.353 に答える
4

あなたの質問は実際には2つの質問のようです。データベースをテストから除外する必要がありますか? データベースを作成する場合、データベース内のデータをどのように生成する必要がありますか?

可能であれば、実際のデータベースを使用することを好みます。CRUD クラスの (SQL、HQL などで記述された) クエリは、実際のデータベースに直面したときに驚くべき結果を返すことがよくあります。これらの問題は早い段階で洗い流すことをお勧めします。多くの場合、開発者は CRUD の非常に薄い単体テストを作成します。最も良性のケースのみをテストします。テストに実際のデータベースを使用すると、認識していない可能性のあるあらゆる種類のコーナー ケースをテストできます。

そうは言っても、他の問題がある可能性があります。各テストの後、データベースを既知の状態に戻す必要があります。私の現在の仕事は、すべての DROP ステートメントを実行し、すべてのテーブルをゼロから完全に再作成することで、データベースを完全に破壊することです。これは Oracle では非常に遅くなりますが、HSQLDB のようなメモリ内データベースを使用すると非常に高速になる可能性があります。Oracle 固有の問題を一掃する必要がある場合は、データベースの URL とドライバーのプロパティを変更して、Oracle に対して実行するだけです。この種のデータベースの移植性がない場合、Oracle には、この目的専用に使用できるある種のデータベース スナップショット機能もあります。データベース全体を以前の状態にロールバックします。他のデータベースに何があるかは確かです。

データベースに含まれるデータの種類に応じて、API またはロード アプローチがうまく機能する場合と機能しない場合があります。多くの関係を持つ高度に構造化されたデータがある場合、API を使用するとデータ間の関係が明確になり、作業が楽になります。テスト データ セットを作成するときに間違いを犯しにくくなります。他の投稿者が述べたように、リファクタリング ツールは、データ構造の変更の一部を自動的に処理できます。多くの場合、API によって生成されたテスト データをシナリオを構成するものと考えると便利です。ユーザー/システムがステップ X、YZ を実行すると、そこからテストが開始されます。ユーザーが使用するのと同じ API を呼び出すプログラムを作成できるため、これらの状態を実現できます。

大量のデータが必要な場合、データ間の関係がほとんどない場合、または API や標準のリレーショナル メカニズムを使用して表現できないデータに一貫性がある場合、データのロードはより重要になります。私のチームで働いていたある仕事は、大規模なネットワーク パケット検査システム用のレポート アプリケーションを作成することでした。当時としてはかなりのデータ量でした。テスト ケースの有用なサブセットをトリガーするために、スニファーによって生成されたテスト データが本当に必要でした。このように、あるプロトコルに関する情報間の相関関係は、別のプロトコルに関する情報と相関します。これを API でキャプチャするのは困難でした。

ほとんどのデータベースには、テーブルの区切りテキスト ファイルをインポートおよびエクスポートするためのツールがあります。しかし、多くの場合、それらのサブセットのみが必要です。データダンプの使用がより複雑になります。私の現在の仕事では、Matlab プログラムによって生成され、データベースに保存される実際のデータのダンプをいくつか取得する必要があります。データベース データのサブセットをダンプし、それをテスト用の「グラウンド トゥルース」と比較できるツールがあります。抽出ツールは常に変更されているようです。

于 2009-02-13T20:05:35.780 に答える
3

何をテストする必要があるかに応じて、両方を行います。

  • SQL スクリプトまたは DB ダンプから静的テスト データをインポートします。このデータは、オブジェクトの読み込み (逆シリアル化またはオブジェクト マッピング) と SQL クエリ テスト (コードが正しい結果を返すかどうかを知りたい場合) で使用されます。

    さらに、私は通常、いくつかのバックボーン データ (構成、ルックアップ テーブルに名前を付けるための値など) を持っています。これらもこのステップでロードされます。このロードは単一のテストであることに注意してください (DB を最初から作成することと一緒に)。

  • DB (オブジェクト -> DB) を変更するコードがある場合、通常は生きている DB (メモリ内またはどこかのテスト インスタンス) に対して実行します。これは、コードが機能することを確認するためです。大量の行を作成しないでください。テストの後、トランザクションをロールバックします (テストでグローバル状態を変更してはならないという規則に従います)。

もちろん、ルールには例外があります。

  • また、パフォーマンス テストで大量の行を作成します。
  • 場合によっては、単体テストの結果をコミットする必要があります (そうしないと、テストが大きくなりすぎてしまいます)。
于 2009-01-27T11:09:14.933 に答える
2

私は通常、SQL スクリプトを使用して、説明したシナリオのデータを入力します。

それは簡単で、非常に簡単に再現できます。

于 2009-01-27T10:18:35.487 に答える
0

これですべての質問に答えられるとは限りませんが、あるプロジェクトで DB に対して単体テストを行うことにしました。私の場合、DB 構造もテストする必要があると感じました。つまり、私の DB 設計はアプリケーションに必要なものを提供しましたか。プロジェクトの後半で、DB 構造が安定していると感じたら、おそらくこれをやめます。

データを生成するために、DB を「ランダムな」データで満たす外部アプリケーションを作成することにしました。個人名や会社名のジェネレーターなどを作成しました。

外部プログラムでこれを行う理由は次のとおりです。 1. テストを変更したデータでテストを再実行できました。つまり、テストを数回実行でき、テストによって行われたデータ変更が有効な変更であることを確認できました。2. 必要に応じて、DB をクリーンアップして、新たなスタートを切ることができます。

このアプローチには失敗点があることに同意しますが、私の場合、たとえば人の生成はテスト用のデータを生成するビジネスロジックの一部であったため、実際にはその部分もテストしていました。

于 2009-01-27T10:19:47.047 に答える