如何在单元测试中断言C#异步方法是否抛出异常?

13

可能是重复问题:
如何使用 NUnit 在 C# 单元测试中测试异步方法,最终使用另一个框架?

我想知道如何在 C# 单元测试中断言异步方法是否抛出异常。我可以使用 Visual Studio 2012 中的 Microsoft.VisualStudio.TestTools.UnitTesting 编写异步单元测试,但是还没有弄清楚如何测试异常。我知道 xUnit.net 也支持以这种方式编写异步测试方法,但我还没有尝试过该框架。

以下代码为测试系统定义了一个示例:

using System;
using System.Threading.Tasks;

public class AsyncClass
{
    public AsyncClass() { }

    public Task<int> GetIntAsync()
    {
        throw new NotImplementedException();
    }
}    

这段代码片段定义了一个名为TestGetIntAsync的测试,用于测试AsyncClass.GetIntAsync。在这里,我需要输入来完成断言,即GetIntAsync是否会抛出异常:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;

[TestClass]
public class TestAsyncClass
{
    [TestMethod]
    public async Task TestGetIntAsync()
    {
        var obj = new AsyncClass();
        // How do I assert that an exception is thrown?
        var rslt = await obj.GetIntAsync();
    }
}

如果需要或者你认为其他单元测试框架比Visual Studio更好,例如xUnit.net,那么可以自由地使用它们。


@JonSkeet 其实不是,因为这是特别关于检查异常的。虽然我现在看到在Visual Studio框架中没有区别。但是对于xUnit.net,我仍然不确定如何做到这一点。 - aknuds1
@JonSkeet 最初我同意,但现在不同意了。如果这个问题正确,即Microsoft的单元测试已经支持异步测试,那么你对另一个问题的回答在这里并不适用。唯一的问题是以这种方式重写测试,使其测试异常。 - user743382
@hvd:在这种情况下,听起来问题与异步无关 - 当然,给出的答案实际上并不依赖于异步部分。 - Jon Skeet
@JonSkeet 就像我说的,我没有意识到 Visual Studio 的单元测试框架是通过方法属性处理这个问题的。我仍然在想如何用 xUnit.net 实现相同的功能,但我想最好还是留待另一个问题来解决... - aknuds1
@JonSkeet 我应该如何使用 Assert.Throws?它不在 Microsoft.VisualStudio.TestTools.UnitTesting 命名空间中吗?此外,显然 xUnit.net 中的 Assert.Throws 必须适用于异步。 - aknuds1
显示剩余2条评论
4个回答

11
请尝试使用标记方法:
[ExpectedException(typeof(NotImplementedException))]

没想到在这个框架中,异常是通过属性来断言的。谢谢! - aknuds1

10

第一个选项是:

try
{
   await obj.GetIntAsync();
   Assert.Fail("No exception was thrown");
}
catch (NotImplementedException e)
{      
   Assert.Equal("Exception Message Text", e.Message);
}

第二个选项是使用预期异常属性:

[ExpectedException(typeof(NotImplementedException))]

第三种选项是使用 Assert.Throws:

Assert.Throws<NotImplementedException>(delegate { obj.GetIntAsync(); });

Assert.IsTrue(true) 的目的是什么? - svick
@svick:没错!我们可以把它移除 :) - CloudyMarble
1
@svick 有些人使用 Assert.IsTrue(true) 来告诉任何阅读代码的人,只要到达代码中的那个点就表示成功了(如果没有 Assert.IsTrue(true),它可能看起来像作者忘记放置一个 Assert)。 - Rune

2
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;

[TestClass]
public class TestAsyncClass
{
    [TestMethod]
    [ExpectedException(typeof(NotImplementedException))]
    public async Task TestGetIntAsync()
    {
        var obj = new AsyncClass();
        // How do I assert that an exception is thrown?
        var rslt = await obj.GetIntAsync();
    }
}

0

尝试使用TPL:

[ExpectedException(typeof(NotImplementedException))]
[TestMethod]
public void TestGetInt()
{
    TaskFactory.FromAsync(client.BeginGetInt, client.EndGetInt, null, null)
               .ContinueWith(result =>
                   {
                       Assert.IsNotNull(result.Exception);
                   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接