5

私は非常に奇妙な問題を扱っています。最初は、これはテスト データのクリーンアップに問題があると思っていましたが、テスト データのクリーンアップ コードを完全にリファクタリングした後も、まったく同じ動作が見られます...途方に暮れています。

さまざまなクラスに 245 個の単体テスト メソッドがあります。各クラスには独自のテスト データがあり、それらのオブジェクトを初期化します。次に、通常、各テスト メソッドでそのデータがデータベースに挿入され、テストで操作されます。各テスト クラスには、データベースからすべてのテスト データをクリーンアップする ClassCleanup メソッドがあり、その ClassCleanup は TestInitialize でも実行され、他のテスト メソッドが実行される前にすべてがクリーンアップされるようにします。

VS 2012 テスト エクスプローラーを使用して「すべて実行」すると、22 個のテストが失敗します。それらはすべて、主キー制約違反のいくつかのバリエーションで失敗します。つまり、これらのテストのデータを初期化するときに、データはそのクラスの以前のテスト メソッドからクリーンアップされませんでした。すべてのテストを再実行すると、毎回同じテストが失敗します。これはかなり再現性があります。すべてのテストを何回実行しても。これらの同じ 27 のテストは、主キー違反で失敗します。

ただし、奇妙なことに、失敗したテストのみを再実行すると、9 つのテストしか失敗しません。これも再現可能です。つまり、以前に失敗した 27 個のテストだけを何度実行しても、14 個は失敗し、残りは成功します。これは、失敗したテストのみを実行し、失敗したテストがなくなるまで続きます。また、各テスト クラスを個別に実行すると、すべてがパスすることにも注意してください。

私はこれがどのように見えるか知っています。

「明らかに、テスト データをクリーンアップしていません。」その場合は、何があっても、すべての実行で同じテストが失敗するはずです。これらの 27 個のテストは、他のすべてを実行したときだけでなく、すべての実行で失敗するはずです。

「クラス間で一意の主キーを持ってはいけません。そうすると、クリーンアップされません。」上記を参照。クラスで主キーが繰り返されていた場合でも(さまざまなクラス内のテストデータの主キーの一意性を個人的にトリプルチェックしたため、そうではありません)、これらのテストは別々のスレッドで同時に実行されないため(これは ThreadId をログに記録することによって確認されています)、特定のテストのクリーンアップ コードは、重複したデータをクリーンアップします。

「接続プーリングを使用していてはなりません。」いいえ、実際に私はそうです。また、SQL プロファイラーを使用して、要求が確実にプールされていることを確認しました。また、これらのテストは並行して実行されないため、接続スレッドは 1 つしかありません。

「接続プーリングは使用しないでください。」基礎となるコードベースはさまざまな Web プロジェクトをサポートしているため、そうする必要がありますが、議論のために、接続プールを無効にして (接続文字列で Pooling=false を使用して) すべてのテストを実行してみましたが、まったく同じ結果が得られました。行動に変化はありません。

「ローカル環境に問題があるはずです。」他の同僚の開発ボックス (ついでに SQL 2012 を使用) でこれらのテストを実行しても、同じ結果が得られます。これは、私の環境や SQL Server のバージョンに固有のものではありません。

「コマンド ラインから mstest を実行してみてください。」すでにそれをしました。同じ結果です。

誰かがこのようなことに遭遇した場合は、私に知らせてください。この種の問題では通常そうであるため、欠けている単純なものがあるに違いないことはわかっていますが、これを整理するために、できる限り多くのベースをカバーしました。

4

2 に答える 2

2

以下は、データベースが完全復旧モードであり、テスト中に復元やその他のトリック (データベースのデタッチ/再アタッチなど) を実行しないという前提に基づいています。

これは、問題を調査するためのかなり退屈なアプローチですが、これを理解するために必要なデータを提供することが保証されています.

  1. データベースのフル バックアップを作成 する テスト スイートを開始する直前にこれを実行します。データベースを復元するので、データベース ファイルのコピーを 2 ~ 3 コピーするのに十分なディスク容量があることも確認してください。

  2. Sql プロファイラー トレースを作成するイベントについては、RPC 開始/完了、SQL バッチ開始/完了、SQL ステートメント開始/完了、SP ステートメント開始/完了、TM:* 完了、SQLTransaction、DTCTransaction、およびユーザー エラー メッセージを選択します。すべての列をキャプチャします。

  3. 問題を再現する 最小限の数のテストを実行して、失敗を生成します。テストを終了させて​​、すべてのクリーンアップ コードをキャプチャしてから、プロファイラー トレースを停止します。

  4. トランザクション ログのバックアップ を作成します。これは、後でポイント イン タイムの復元に必要になる場合があります。

  5. トレースで障害を特定 する 主キーの障害が発生している場合は、簡単に追跡できます。ユーザー エラー メッセージを探すだけです。エラーが発生した正確な時刻を書き留めます。

  6. 明らかな問題がないかトレースを 調べます エラーから開始し、失敗したテストの開始点が見つかるまで逆方向に作業します。最後に失敗したテストのセットアップが開始された正確な時刻を書き留めます。この範囲内のすべての SQL を調べます。SQLはまさにあなたが期待するものですか? 行数は正しいですか?transactionId は正しいですか? ( transactionId 列は、トランザクション内にないすべてのステートメントで異なり、トランザクションのすべてのステートメントで同じである必要があります)。BEGIN TRAN/COMMIT TRAN/ROLLBACK TRAN が一致しない場合は、transactionId で通知されます。

  7. 失敗したテスト セットアップの直前に DB を 復元する 新しいデータベースに復元して、元のデータベースとコピーを比較できるようにします。まず、「RESTORE DATABASE .... WITH NORECOVERY」を使用して完全バックアップを復元します。次に、「RESTORE LOG .. WTIH STOPAT, RECOVERY」を使用してトランザクション ログ バックアップを復元し、失敗したテスト セットアップの直前の時刻を指定します。

  8. データベースの状態 を確認する クリーンアップされていない可能性のあるテスト データを確認します。すべてはあるべき姿ですか?そうでない場合は、データベースを以前の時点に再度復元できます。データベースが良好で既知の状態にあるテスト開始直前の時点を探しています。

  9. DB をエラー発生直前にリストアする 余裕があれば、別の新しい DB にリストアします。PK 違反の原因となったデータを確認します。問題のあるステートメントを再度実行すると、エラーが発生しますか? 発生するか発生しないかを確認します。

    • 発生しない場合、問題はトランザクション処理の不一致である可能性があります。以前に COMMIT が見つからなかった場合は、トランザクションがまだ開いている可能性があります。STOPAT で復元すると、コミットされていないトランザクションはロールバックされます。これは、テストを個別に実行する方法も説明しますが、一緒に失敗します。
    • 問題が発生した場合は、問題が見つかるまで逆方向に作業します。それを理解する前に、DB を複数回復元する必要がある場合があります。あなたのプロセスは、DBの復元、トレースの調査、データの調査、別のポイントへの復元、トレースの調査、データの調査などです。
  10. それでもまだ途方に暮れている場合は、単体テストの一部としてデータベース スナップショットを使用して調査することをお勧めします。基本的に、db スナップショットを作成し、セットアップしてテストを実行します。ティアダウンは、データベースをスナップショットに戻すことに置き換えられます。これにより、各テストの前後で同一のデータベースが保証されます。

2012 Management Studio には、ポイント イン タイム リストアを非常に簡単にする改善されたデータベース リストア ウィザードがあります。 幸運を!

于 2013-04-19T06:25:22.287 に答える
0

あなたのものが失敗する理由はわかりませんが、私は似たようなものを持っていたので、次transactionscopeのようにセットアップに入れました:

public void SetUp()
{
 _transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
}

そして分解で処分します。これにより、データベースの問題が解消され、手動でクリーンアップ コードを作成する必要がなくなりました。

于 2013-04-11T20:47:30.617 に答える