NUnit,既不是Assert.Throws也不是[ExpectedException] Catch Thrown Exception

时间:2011-01-21 17:17:52

标签: .net exception tdd nunit-2.5

在开始之前,我想明确表示我已经检查了this questionthis 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);
    }
}

1 个答案:

答案 0 :(得分:3)

我的猜测是你并没有真正测试你认为自己的代码。尝试放入一些Console.WriteLine语句并查看它们是否已打印。如果在throw语句上放置断点并在调试器中运行测试,断点是否会被命中?如果控制传递给下一个语句,那意味着永远不会抛出异常 - 它不可能以一种让抛出方法继续执行的方式被捕获,除非你发现真的奇怪的CLR错误。

我已经编写了很多这样的代码,它在NUnit中从未失败过。

顺便说一下,我认为在ArgumentExceptions中包含参数名称是个好习惯,所以我写了:

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

这有一个令人遗憾的问题,就是长途跋涉并将代码中的参数名称重复为字符串......但是它很容易合适(尤其是ReSharper帮助验证名称),如果这样做的话,这可能非常有用在生产中触发。 (有一些难以理解的黑客以其他方式验证这些论点,但我怀疑你不想看到那些......)