1

在开始之前,我想明确一点,我已经检查过这个问题这个问题的解决方案。

测试方法

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)
    );
}

奇怪的行为

这两个版本的测试方法都没有捕捉到ArgumentNullException在进入方法时立即抛出的那个ExecuteDataSet。控制流进行到下一行 ( using (var command = connection.CreateCommand())) 并且NullReferenceException发生了 a (当然,我的任何一个测试用例都没有处理它,因为它永远不应该被抛出)。

最初,第一个测试方法 ( 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);
    }
}
4

1 回答 1

3

我的猜测是,您并没有真正测试您认为的代码。试着把一些Console.WriteLine语句放进去,看看它们是否被打印出来。如果在throw语句上设置断点并在调试器中运行测试,断点会被命中吗?如果控制权传递给下一条语句,则意味着永远不会抛出异常 - 除非您发现了一个非常奇怪的 CLR 错误,否则不可能以允许在抛出方法中继续执行的方式捕获它。

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

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

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

这有一个不幸的问题是冗长并将代码中的参数名称作为字符串重复......但它相当容易正确(尤其是使用 ReSharper 帮助验证名称)并且如果这在生产中触发它可能会非常有用. (有一些奇怪的黑客可以以其他方式验证论点,但我怀疑你不想看到那些......)

于 2011-01-21T17:33:40.130 回答