2011-01-24 5 views
12

私は遭遇した問題を分離して実証する簡単なテストプログラムを考案することを提案した著名なJohn Skeet氏の要請により、この質問を新たに投稿しています。この質問はthis oneから生まれました。とても親しみがあるように聞こえたら私を許してください。あなたはこの質問に関する追加の詳細を潜在的に収集することができます。NUnit:なぜAssert.Throwsしません<T>私のArgumentNullExceptionをキャッチですか?

NUnit 2.5.9からAssert.Throws<T>の問題が発生しました。場合によっては、例外をTestDelegateによって呼び出されたメソッドでスローすることができません。私は以下のコードでこの振る舞いを再現可能な方法で固定しています。 。(™これは、確かにあってもよいの場合は、私のマシンで失敗するものの

エラーを再現するために、私は2つのC#のDLLプロジェクトとソリューションを作成しました:

  • 最初は1つのクラスを含んでいます、このメソッドは、SqlCommandを作成するために必要なロジックをカプセル化し、そのパラメータを設定し、ExecuteScalarを呼び出す拡張メソッドです。
  • 2つ目は、2つのメソッド最初のDLLのメソッドが期待どおりに動作しているかどうかをテストします。 NUnitフレームワークを参照してください。他のアセンブリは参照されません。私は、デバッガでテストをステップ実行すると

、私は次のことを守ってください。

  1. Assert.Throwsは正しくExecuteScalar<T>拡張メソッドを呼び出します。
  2. パラメータ値は、期待どおりにNULLです。
  3. ExecuteScalar<T>は、ヌル値のパラメータをテストします。
  4. デバッガはヒットし、throw new ArgumentNullException(...)を含む行を実行します。
  5. throwの実行後、アプリケーションの制御はすぐにAssert.Throwsに転送されません。代わりに、それはExecuteScalar<T>の次の行に続きます。
  6. 次のコード行が実行されるとすぐに、デバッガがブレークし、「引数null例外がユーザーコードによって処理されませんでした」というエラーが表示されます。

この動作を分離するソースコードを以下に示します。

拡張メソッド

namespace NUnit_Anomaly 
{ 
    using System; 
    using System.Data; 
    using System.Data.SqlClient; 

    public static class Class1 
    { 
     public static T ExecuteScalar<T>(this SqlConnection connection, string sql) 
     { 
      if (connection == null) 
      { 
       throw new ArgumentNullException("connection"); 
      } 

      if (sql == null) 
      { 
       throw new ArgumentNullException("sql"); 
      } 

      using (var command = connection.CreateCommand()) 
      { 
       command.CommandType = CommandType.Text; 
       command.CommandText = sql; 
       return (T)command.ExecuteScalar(); 
      } 
     } 
    } 
} 

テストケース

namespace NUnit_Tests 
{ 
    using System; 
    using System.Data.SqlClient; 
    using System.Diagnostics; 

    using NUnit.Framework; 

    using NUnit_Anomaly; 

    [TestFixture] 
    public class NUnitAnomalyTest 
    { 

     [Test] 
     public void ExecuteDataSetThrowsForNullConnection() 
     { 
      Assert.Throws<ArgumentNullException>(() => ((SqlConnection)null).ExecuteScalar<int>(null)); 
     } 

     [Test] 
     public void ExecuteDataSetThrowsForNullSql() 
     { 

      const string server = "MY-LOCAL-SQL-SERVER"; 
      const string instance = "staging"; 
      string connectionString = String.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;", 
                server, 
                instance); 

      using (var connection = new SqlConnection(connectionString)) 
      { 
       Assert.Throws<ArgumentNullException>(() => connection.ExecuteScalar<int>(null)); 
      } 
     } 
    } 
} 

正味の効果は、とき、彼らはいけないテストが失敗していることです。私の理解の中で、Assert.Throws<T>は私の例外を捕らえるべきで、テストは合格しなければなりません。

UPDATE

私はハンスの助言を取り、例外]ダイアログを確認しました。私は例外を投げて例外をスローしていませんでしたが、私は未処理のユーザ例外を壊していました。どうやら、例外がスローされたときにデバッガがIDEに壊れてしまうのです。チェックボックスをオフにすると問題が解決され、Assert.Throws<T>が選択されました。しかし、これをやっていないと、F5を押して実行を続けることはできません。例外はNullReferenceExceptionになります。

ここで問題は次のとおりです。プロジェクトごとに例外ブレークを設定できますか?私はテストをしているときだけこれをしたいが、一般的ではない。

+1

Debug + Throwチェックボックスがオフになっていることを確認してください。 –

+0

@ Hans Passant:私は、Thrownチェックボックスのどれもチェックされていないことを確認しました。 –

答えて

15

実際に何が起こるかはAssert.Throwsがあなたの例外をキャッチしないこと、しかし、Visual Studioは、とにかく初回例外で停止しています。 F5キーを押すだけでこれを確認できます。 Visual Studioは楽しく実行し続けます。

例外ヘルパーから通知されたように、例外はユーザコードによって未処理のでした。そのため、Visual Studioでは何らかの理由でNUnitがユーザーコードであるとは考えていません。

enter image description here

あなたが見てどこを知っていれば

Visual Studioが実際に、プレーンテキストで、あなたにこれを伝えます:

:また、スタックトレースでこの事実の証拠がある

enter image description here

enter image description here

解決策1:NUnitのデバッグビルドをシンボルのデバッグに使用します。それはwill get Visual Studio to regard NUnit as user codeであり、あなたの例外を "未処理のユーザーコード"として扱いません。これは簡単ではありませんが、長期的にはよりうまくいくかもしれません。

ソリューション2:Visual Studioのデバッグの設定で "マイコードのみを有効にする" のチェックボックスをオフにします。

enter image description here

P.S.私は回避策を考えずに、Assert.Throws<T>の使用を避けていますが、それを行う方法はもちろんあります。

+0

私はnunit-console.exeを使用していますが、VSデバッガを使用していません。私はデバッグモードのコードを実行していません。 NUnitが例外をキャッチしていない場合、これは何か意味がありますか? –

+0

@GrantBirchmeierあなたは別の問題を抱えているかもしれませんが、新しい質問をしてそこに詳細を提供することをお勧めします。 –

+0

それは私のすべてのユーザーエラーでした。 –

関連する問題