在开始之前,我想明确表示我已经检查了this question和this question中的解决方案。
测试方法
public static DataSet ExecuteDataSet(this SqlConnection connection, string sql)
{
if (null == connection || null == sql)
{
throw new ArgumentNullException();
}
using (var command = connection.CreateCommand())
{
// Code elided for brevity
}
}
测试方法
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ExecuteDataSetThrowsForNullConnection()
{
((SqlConnection)null).ExecuteDataSet("SELECT TOP 1 * FROM prep");
}
[Test]
public void ExecuteDataSetThrowsForNullSql()
{
Assert.Throws<ArgumentNullException>(
() => Resource.Connection.ExecuteDataSet(null)
);
}
奇怪行为
test 方法的任何一个版本都没有捕获在输入ArgumentNullException
方法后立即引发的ExecuteDataSet
。控制流程继续进行到下一行(using (var command = connection.CreateCommand())
)并且正在发生NullReferenceException
(当然,我的任何一个测试用例都没有处理它,因为它永远不会被抛出< / em>的)。
最初,第一种测试方法(ExecuteDataSetThrowsForNullConnection
)看起来就像第二种测试方法(ExecuteDataSetThrowsForNullSql
)。当Assert.Throws
未能发现异常时,我做了一些研究并注意到有些人建议使用ExpectedException
代替。我相应地修改了测试代码,但无济于事。
为了记录,这是32位.NET 3.5代码,在NUnit 2.5.9下测试。我正在使用TestDriven.NET进行Visual Studio集成,并安装了最新版本的NCover和NDepend。
TL; DR问题
为什么测试方法没有捕获抛出的异常,我该如何修复它?
修改
此版本的测试方法有效。
[Test]
public void ExecuteDataSetThrowsForNullConnection()
{
try
{
((SqlConnection)null).ExecuteDataSet("SELECT TOP 1 * FROM prep");
}
catch(ArgumentNullException e)
{
Assert.AreEqual(true, true);
}
catch (Exception e)
{
Assert.Fail("Expected ArgumentNullException, but {1} was thrown instead.", e.GetType().Name);
}
}
答案 0 :(得分:3)
我的猜测是你并没有真正测试你认为自己的代码。尝试放入一些Console.WriteLine
语句并查看它们是否已打印。如果在throw
语句上放置断点并在调试器中运行测试,断点是否会被命中?如果控制传递给下一个语句,那意味着永远不会抛出异常 - 它不可能以一种让抛出方法继续执行的方式被捕获,除非你发现真的奇怪的CLR错误。
我已经编写了很多这样的代码,它在NUnit中从未失败过。
顺便说一下,我认为在ArgumentExceptions中包含参数名称是个好习惯,所以我写了:
if (connection == null)
{
throw new ArgumentNullException("connection");
}
if (sql == null)
{
throw new ArgumentNullException("sql");
}
这有一个令人遗憾的问题,就是长途跋涉并将代码中的参数名称重复为字符串......但是它很容易合适(尤其是ReSharper帮助验证名称),如果这样做的话,这可能非常有用在生产中触发。 (有一些难以理解的黑客以其他方式验证这些论点,但我怀疑你不想看到那些......)