我如何单元测试这种(正确)抛出异常的异步方法?

时间:2014-03-14 10:39:55

标签: c# .net unit-testing async-await

我在界面中有以下方法..

Task<SearchResult<T>> SearchAsync(TU searchOptions);

效果很好。

现在我正在尝试进行单元测试,以便在出现问题时进行测试 - 并且代码会抛出异常。

在这种情况下,我设置了我的方法来抛出HttpRequestException。我的单元测试未能说我扔了那个例外..

var result = Should.Throw<HttpRequestException>
    (async () => await service.SearchAsync(searchOptions));

单元测试的错误消息是

  

Shouldly.ChuckedAWobbly
  var result =应该是           扔
      System.Net.Http.HttpRequestException
          但不是

所以assertion framework说的是:你预料到一个例外,但没有一个被抛出。

当我逐步执行代码时,异常被100%抛出。

有人能看到我的单元测试代码出错吗?

6 个答案:

答案 0 :(得分:13)

问题是您的断言框架不了解异步方法。我建议你提出问题。

与此同时,您可以使用source for Should.Throw撰写自己的MyShould.ThrowAsync

public static async Task<TException> ThrowAsync<TException>(Func<Task> actual)
    where TException : Exception
{
  try
  {
    await actual();
  }
  catch (TException e)
  {
    return e;
  }
  catch (Exception e)
  {
    throw new ChuckedAWobbly(new ShouldlyMessage(typeof(TException), e.GetType()).ToString());
  }

  throw new ChuckedAWobbly(new ShouldlyMessage(typeof(TException)).ToString());
}

并按原样使用:

var result = await MyShould.ThrowAsync<HttpRequestException>
    (async () => await service.SearchAsync(searchOptions));

或稍微简单和等效:

var result = await MyShould.ThrowAsync<HttpRequestException>
    (() => service.SearchAsync(searchOptions));

答案 1 :(得分:3)

单元测试异步代码/功能非常困难。我自己正在进行单元测试异步并遇到与你一样的问题。

我发现以下两个资源非常有用:

答案 2 :(得分:3)

问题是传递的lambda返回一个Task。如果Should.Throw等待完成此任务,则只能观察到引发的异常,显然它不会。作为解决方法,您可以.Wait自己SearchAsync返回任务。{/ p>

mstest(内置的visual studio测试框架)支持自Visual Studio 2012以来的异步测试。您基本上可以通过替换&#34; void&#34;来更改测试方法声明。 by&#34; async Task&#34;。

[TestMethod]
[ExpectedException(typeof(System.Net.Http.HttpRequestException))]
public async Task SomeTest()
{
   await service.SearchAsync(searchOptions);
}

您可能正在使用不同的单元测试框架,但不清楚哪一个。请查阅其文档以了解它是否支持异步测试。

NUnit 2.6.3似乎也支持异步测试。

编辑:所以您正在使用xUnit。这个特殊问题是fixed for xUnit 2.0。它目前仍然是阿尔法。

答案 3 :(得分:2)

异常抛出在与运行单元测试的线程不同的线程上。单元测试框架只能预测其自己的线程上的异常。

我建议您在服务的同步版本上测试异常。

答案 4 :(得分:2)

像这样测试:

var result = Should.Throw<HttpRequestException>
    (() => service.SearchAsync(searchOptions).Result);

或者:

var result = Should.Throw<HttpRequestException>
    (() => service.SearchAsync(searchOptions).Wait());

否则,Should.Throwasync lambda完成之前返回。

答案 5 :(得分:0)

今天应该包含Should.ThrowAsync<T>

您可以像这样使用它:

await Should.ThrowAsync<HttpRequestException>(() => service.SearchAsync(searchOptions));