简体   繁体   English

NUnit,Assert.Throws或[ExpectedException]都不引发抛出异常

[英]NUnit, Neither Assert.Throws nor [ExpectedException] Catch Thrown Exception

Before I start, I want to make it clear that I've already checked for solutions in both this question and this question . 在开始之前,我想说明一下,我已经检查了这个问题这个问题的解决方案。

The Method to Test 测试方法

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

The Test Methods 测试方法

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

The Odd Behavior 奇怪的行为

Neither version of the test method is catching the ArgumentNullException that is thrown immediately upon entering the ExecuteDataSet method. 测试方法的两个版本均未捕获进入ExecuteDataSet方法后立即引发的ArgumentNullException Control flow proceeds to the next line ( using (var command = connection.CreateCommand()) ) and a NullReferenceException is occurring instead (which, of course, isn't handled by either of my test cases because it should never be thrown ). 控制流前进到下一行( using (var command = connection.CreateCommand()) ),而发生了NullReferenceException (当然,这两个测试用例都不会对其进行处理,因为它永远都不会抛出 )。

Originally, the first test method ( ExecuteDataSetThrowsForNullConnection ) looked just like the second one ( ExecuteDataSetThrowsForNullSql ). 最初,第一个测试方法( ExecuteDataSetThrowsForNullConnection )看起来就像第二个测试方法( ExecuteDataSetThrowsForNullSql )。 When Assert.Throws failed to catch the exception, I did some research and noted that some folks recommended using ExpectedException instead. Assert.Throws无法捕获该异常时,我进行了一些研究,并指出一些人建议改用ExpectedException I modified the test code accordingly, but to no avail. 我相应地修改了测试代码,但无济于事。

For the record, this is 32-bit .NET 3.5 code, tested under NUnit 2.5.9. 作为记录,这是在NUnit 2.5.9下测试的32位.NET 3.5代码。 I'm using TestDriven.NET for Visual Studio integration, and have the latest versions of NCover and NDepend installed. 我正在使用TestDriven.NET进行Visual Studio集成,并安装了最新版本的NCover和NDepend。

TL;DR Question TL; DR问题

Why aren't the test methods catching the exception that is thrown, and how do I fix it? 为什么测试方法没有捕获到抛出的异常,我该如何解决?

EDIT 编辑

This version of the test method works. 此版本的测试方法有效。

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

My guess is that you're not really testing the code you think you are. 我的猜测是您并未真正测试您认为的代码。 Try putting some Console.WriteLine statements in and see if they're printed. 尝试放入一些Console.WriteLine语句,看看它们是否已打印。 If you put a breakpoint on the throw statement and run the tests in the debugger, does the breakpoint get hit? 如果在throw语句上放置一个断点并在调试器中运行测试,该断点会命中吗? If control is passing to the next statement, that means the exception is never being thrown - it can't possibly be caught in a way which would let execution continue in the throwing method, unless you've found a really weird CLR bug. 如果将控制权传递给下一条语句,则意味着永远不会引发异常-除非您发现了一个非常奇怪的CLR错误,否则无法以允许在执行throwing方法中继续执行的方式捕获该异常。

I've written lots of code like this and it's never failed in NUnit. 我已经写了很多这样的代码,并且在NUnit中从未失败过。

As an aside, I view it as good practice to include the parameter name in ArgumentExceptions, so I'd have written: 顺便说一句,我认为在ArgumentExceptions中包含参数名称是一种很好的做法,所以我会写:

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

This has the unfortunate problem of being longwinded and repeating the parameter names in the code as strings... but it's reasonably easy to get right (especially with ReSharper helping to validate the names) and it could be really useful if this ever triggers in production. 不幸的是,这个问题很冗长,并且在代码中以字符串形式重复了参数名称...但是这样做很容易就可以正确使用(尤其是在ReSharper帮助验证名称的情况下),并且如果这在生产中触发的话,它可能会非常有用。 。 (There are some grotty hacks to validate the arguments in other ways, but I suspect you don't want to see those...) (有一些怪异的技巧可以通过其他方式验证参数,但我怀疑您不想看到这些...)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM