我在尊敬的John Skeet先生的指示下重新發布了這個問題,他建議我設計一個簡單的測試程序來隔離並演示我遇到的問題並重新發布問題。這個問題從this one開始,所以請原諒我,如果這聽起來很熟悉。你可能會從這個問題收集關於這個問題的額外細節。NUnit:爲什麼不Assert.Throws <T> Catch My ArgumentNullException?
我遇到的問題來自NUnit 2.5.9的Assert.Throws<T>
。有時,它將無法捕獲由TestDelegate調用的方法中拋出的任何異常。我已經在下面的代碼中以可重現的方式固定了這種行爲。 (雖然這可能,誠然,是無法在我的機器的情況下™
重現錯誤,我已經創建了兩個C#DLL項目的解決方案:
- 第一個包含一類,這個方法是一個擴展方法,它封裝了創建一個
SqlCommand
所需的邏輯,填充它的參數並調用ExecuteScalar
就可以了,這個項目不包含其他的參考信息 - 第二個包含一個具有兩個方法的類它測試第一個DLL中的方法是否按預期工作,該項目引用第一個,幷包含ar參考NUnit框架。沒有其他程序集被引用。
當我通過在調試器中測試步驟,我觀察到以下:
Assert.Throws
正確調用ExecuteScalar<T>
擴展方法。- 參數值爲空,如預期。
ExecuteScalar<T>
測試其空值參數。- 調試器確實命中並執行包含
throw new ArgumentNullException(...)
的行。 - 執行
throw
之後,應用程序的控制權不會立即轉移到Assert.Throws
。相反,它繼續在ExecuteScalar<T>
的下一行。 - 只要下一行代碼執行,調試程序就會中斷,並顯示錯誤「參數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
。
所以現在的問題是:我可以在每個項目的基礎上配置異常中斷嗎?我只想在測試時這樣做,但不是一般。
調試+異常,確保投擲複選框關閉。 – 2011-01-24 18:21:30
@Hans Passant:我已經確認沒有選中Thrown複選框。 – 2011-01-24 18:32:59