NUnit的,无论是Assert.Throws也不[ExpectedException]捕获抛出异常 [英] NUnit, Neither Assert.Throws nor [ExpectedException] Catch Thrown Exception

查看:235
本文介绍了NUnit的,无论是Assert.Throws也不[ExpectedException]捕获抛出异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我开始之前,我想清楚地表明,我已经检查了两个<一个解决方案href="http://stackoverflow.com/questions/639813/expectedexception-not-catching-exception-but-i-can-catch-it-with-try-catch">this问题和<一href="http://stackoverflow.com/questions/2516622/nunit-assert-thatmethod-throws-exception-not-catching-exceptions">this问题。

的方法来测试

 公共静态数据集ExecuteDataSet(这SqlConnection的连接字符串SQL)
{
    如果(空==连接||空== SQL)
    {
        抛出新ArgumentNullException();
    }

    使用(VAR命令= connection.CreateCommand())
    {
        // code省略为简洁起见
    }
}
 

测试方法

  [测试]
[ExpectedException(typeof运算(ArgumentNullException))]
公共无效ExecuteDataSetThrowsForNullConnection()
{
    ((SqlConnection的)空).ExecuteDataSet(SELECT TOP 1 * FROM preP);
}

[测试]
公共无效ExecuteDataSetThrowsForNullSql()
{
    Assert.Throws&LT; ArgumentNullException&GT;(
        ()=&GT; Resource.Connection.ExecuteDataSet(空)
    );
}
 

的奇怪行为

无论是版本的测试的方法捕捉 ArgumentNullException 是在进入立即抛出的 ExecuteDataSet 方法。控制流程前进到下一行(使用(VAR命令= connection.CreateCommand()))和的NullReferenceException 是发生的,而不是(当然,不被任何我的测试案例处理,因为的它不应该被抛出的)。

本来,第一个测试方法( ExecuteDataSetThrowsForNullConnection )看起来就像第二个(ExecuteDataSetThrowsForNullSql <$ C C $>)。当 Assert.Throws 没能赶上例外,我做了一些研究,并指出,一些人推荐使用 ExpectedException 代替。我修改了测试code相应地,但都无济于事。

有关的记录,这是32位的.NET 3.5 code,NUnit的2.5.9下进行测试。我使用TestDriven.NET的Visual Studio集成,并有NCover和NDepend的最新版本安装。

TL; DR问题

为什么不是测试方法捕获时引发的异常,以及如何解决呢?

修改

该版本的测试方法的工作原理。

  [测试]
公共无效ExecuteDataSetThrowsForNullConnection()
{
    尝试
    {
        ((SqlConnection的)空).ExecuteDataSet(SELECT TOP 1 * FROM preP);
    }
    赶上(ArgumentNullException E)
    {
        Assert.AreEqual(真实的,真正的);
    }
    赶上(例外五)
    {
        Assert.Fail(预期ArgumentNullException,但{1}被抛出来代替。e.GetType()名称。);
    }
}
 

解决方案

我的猜测是,你没有真正测试code,你以为你是。尝试把一些 Console.WriteLine 语句,看看他们是否打印。如果你把一个断点上的抛出语句,并运行在调试器中测试,并断点得打?如果控制传递给下一个语句,这意味着异常永远不会被抛出 - 它不可能陷入这将让投掷方法执行下去,除非你找到一个的真的怪异的CLR的错误。

我写的大量的code这样的的,它从来没有在NUnit的。

顺便说一句,我认为这是很好的做法,包括在ArgumentExceptions参数名,所以我写了:

 如果(连接== NULL)
{
    抛出新ArgumentNullException(连接);
}
如果(SQL == NULL)
{
    抛出新ArgumentNullException(SQL);
}
 

这有被冗长和code字符串重复参数名不幸的问题...但它相当容易得到的权利(特别是ReSharper的帮助,以验证名称),这可能是真正有用的如果这曾经引发生产。 (有一些难看黑客以验证在其他方面的观点,但我怀疑你不想看到这些......)

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. 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).

Originally, the first test method (ExecuteDataSetThrowsForNullConnection) looked just like the second one (ExecuteDataSetThrowsForNullSql). When Assert.Throws failed to catch the exception, I did some research and noted that some folks recommended using ExpectedException instead. 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. I'm using TestDriven.NET for Visual Studio integration, and have the latest versions of NCover and NDepend installed.

TL;DR Question

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. If you put a breakpoint on the throw statement and run the tests in the debugger, does the breakpoint get hit? 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.

I've written lots of code like this and it's never failed in NUnit.

As an aside, I view it as good practice to include the parameter name in ArgumentExceptions, so I'd have written:

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. (There are some grotty hacks to validate the arguments in other ways, but I suspect you don't want to see those...)

这篇关于NUnit的,无论是Assert.Throws也不[ExpectedException]捕获抛出异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆