2013-07-25 13 views
5

私はサービスのテスト自動化に取り組んでいて、いくつかの一般的なセットアップ&検証を 'セッション'クラスにロールアップするうまい方法を考え出しました。私は等の役割ごとに適切な認証をテストしていたサービスへの接続を設定Sessionオブジェクトのコンストラクタで例外が既にスローされているかどうかを確認するにはどうすればよいですか?

using (var managerSession = new Session(managerRole)) 
{ 
    // A manager puts some items in warehouse 
} 

using (var employeeSession = new Session(employeeRole)) 
{ 
    // An employee moves items from warehouse to store 
} 

using (var customerSession = new Session(customerRole)) 
{ 
    // A customer can buy items from the store 
} 

を、そしてセッション廃棄で:

概念的には、テストケースは次のようになります。 ()メソッドセッションのライフタイム中にサーバー側のエラーや警告が発生していないかどうかをチェックする共通の検証ブロックがあります。

もちろん、これはIDisposeパターンを悪用しています。使用ブロック内のテストコードが例外をスローし、検証ブロックも例外をスローすると、2番目の例外が最初にマスクされます。概念的に

、私たちはこのシナリオがある場合:

using (var managerSession = new Session(managerRole)) 
{ 
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job"); 
} 

を...とアサートが失敗したかmanagerSession.DoJob()の呼び出しが例外をスローし、その後、私はセッションのDispose()メソッドをしたいと思います検証ブロックをスキップし、すなわち

public void Dispose() 
{ 
    if (NoExceptionThrown()) 
    { 
     Assert.IsFalse(this.serviceConnection.HasErrors(), "Service connection has errors"); 
    } 

    this.serviceConnection.Dispose(); 
} 

...それは実際に失敗した場合の試験方法は、「サービスの接続にエラーがある」で失敗したことがないというような「マネージャー彼の仕事をしませんでした」

私の質問です:ここで 'NoExceptionThrown()'メソッドを実装することは可能ですか?チェックすることができるいくつかのグローバルプロパティ、またはThread.CurrentThreadで隠されているものが利用できますか?

更新:

私の質問は、私はもちろんの代わりにこのパターンを使用することができ、この:-)に

をリファクタリングする方法ないです:静的メソッドForRole(有

Session.ForRole(managerRole, (session) => { /* Test code here */ }); 

を)同様に定義される。

public static void ForRole(Role r, Action<Session> code) 
{ 
    var session = new Session(r); 
    try 
    { 
     code(session); 
     Assert.IsFalse(session.serviceConnection.HasErrors()); 
    } 
    finally 
    { 
     session.Dispose(); 
    } 
} 

しかし、上記のように例外状態を取得する方法があるかどうか不思議です。

+2

2つのもの。まず、はい、これは 'IDisposable'を乱用しています。 「IDisposable」を使用して、「できるだけ早く解放すべき管理されていないリソースを所有しています。何かを意味すると、コードを読みにくくします。第二に、あなたは* any * exception、またはuncaught * exceptionsのみを心配していますか?テストコードが例外をスローし、キャッチして正常に完了したとします。それにフラグを立てるべきでしょうか? –

+0

ああ、私は_uncaught_例外についてのみ心配しています。私は質問を更新します... – Christoffer

+0

乱用IDisposableについて:私は実際には、エラーの潜在的なマスキングよりも各セッションの共通の検証が欠落していることを心配しています。実際のテストコードブロックは10〜100行のUIオートメーションコードであり、ブロックの1つで妥当性検査ステップの1つが欠落している(または誤ったブロックで報告されている)ため、検出されなかった欠陥を既に検出しています。 – Christoffer

答えて

1

があれば、そのクリーンアップに関連したfinallyコンテキストで保留されたものを除いて、示すためにタイプExceptionのパラメータを取っIDisposable.Disposeの過負荷が発生した場合には参考になりましたでしょう。Disposeメソッドは一般的に例外の詳細を気にするべきではありませんが、呼び出し側に報告する必要があるメソッドの間に条件が発生する可能性があります。 Disposeからスローされた例外は、呼び出し側のfinallyコンテキストで保留されていた例外を置き換えます。したがって、Disposeメソッドは、保留中の例外を置き換える前にカプセル化できます。残念ながら、このような機能は存在せず、私は何も追加される予定はありません。

目的の効果のようなものを達成するために使用されるハックがいくつかありますが、意味的に正しい方法は、例外をDisposeメソッドのパラメータにすることだけです。他の方法の問題は、複数のネストされたfinallyブロック内で実行される可能性があります。ブロックの中には保留中の例外があり、その中にはブロックされないものがあります。最も深くネストされたfinallyブロックの状態を判定するために実行コンテキストを検査するコードは、そのブロックが廃棄されるオブジェクトの有効期間を守るブロックでない場合に失敗する可能性があります。

+0

私はこの答えを最も正しいものとして受け入れると思う – Christoffer

0

あなたのクラスにブール値(デフォルトはfalse)を設定するのは確かですが、醜いことです。

using (var managerSession = new Session(managerRole)) 
{ 
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job"); 
    managerSession.NoExceptionThrown = true; 
} 

私はあなたのIDisposableパターンではるかにきれいになるとは思わない。

この例では、try ... catch ...は、例外オブジェクトに直接アクセスできるため、最終的にはうまくいくかもしれません。例外オブジェクトはnull-ness(つまり単語ですか?後で使用するために保管することもできます。 usingはtry catchのための単なる砂糖なので、何も失うべきではありません。

+1

はい、ヌルネスは完璧な発色語です。 – Christoffer

+0

さらに深刻な発言のために、Disposeメソッドの検証ブロックを制御するプロパティを設定することは、実際にはあまり良い考えではありません。とにかく使用ブロックごとに何かを追加する場合は、既存の検証コードを別のメソッドにリファクタリングしてスコープを閉じる前に呼び出すほうがよいでしょう。 – Christoffer

+0

@Christofferええ、私はあなたが使用して丸型のプラグイン・ア・スクエア・ホールのもの。 supercatが指摘しているように、適切な方法は、例外オブジェクトを渡すか、例外が発生したかどうかを示すことです。だから、私はあなたが適切なメソッドを追加することができたと思う、ちょうど使い捨てとDispose(例外)を自分で呼び出しますか?そこにも問題があります。私は、あなたが欲しがっていることを踏み外したり、頭を後ろ向きにしたりすることなく、言語があなたの望むものになるように強制することはできないだろうと考えています。そして、私が知る限り、キャッチブロックの外に例外がないかチェックする方法はありません。 – Xcelled194

関連する問題