3

我进行了以下 xUnit 测试,该测试使用 HttpClient 在网络服务器上调用状态 API 方法。

[Fact]
public void AmIAliveTest()
{
    var server = TestServer.Create<Startup>();

    var httpClient = server.HttpClient;
    var response = httpClient.GetAsync("/api/status").Result;

    response.StatusCode.Should().Be(HttpStatusCode.OK);
    var resultString = response.Content.ReadAsAsync<string>().Result;

    resultString.Should().Be("I am alive!");
}

该测试在本地运行良好。但是当我提交代码并尝试在 TeamCity 构建服务器上运行相同的测试时,它会永远运行。我什至不得不杀死 xunit runner 进程,因为停止构建不会停止这个进程。

但是,当我这样编写测试时

[Fact]
public async void AmIAliveTest()
{
   var server = TestServer.Create<Startup>();

   var httpClient = server.HttpClient;
   var response = await httpClient.GetAsync("/api/status");

   response.StatusCode.Should().Be(HttpStatusCode.OK);
   var resultString = await response.Content.ReadAsAsync<string>();

   resultString.Should().Be("I am alive!");
}

它在本地和 TeamCity 上运行良好。

我现在担心的是我忘记像第二个变体那样编写测试,并且有时 teamcity 构建会挂起。

谁能向我解释为什么在teamcity buildserver上运行的xUnit一开始就没有正确运行测试?有没有办法解决这个问题?

4

2 回答 2

7

谁能向我解释为什么在teamcity buildserver上运行的xUnit一开始就没有正确运行测试?

首先,我会检查您的 xUnit 版本——您应该运行的是最近发布的 2.0。我怀疑您的本地版本可能已过时。

核心问题在这一行:

var resultString = response.Content.ReadAsAsync<string>().Result;

我怀疑您遇到了我在博客中描述的僵局情况。HttpClient在某些平台上有一些方法没有正确使用ConfigureAwait(false),因此会出现这种死锁。xUnit 2.0 将单线程安装SynchronizationContext到其所有单元测试中,这提供了死锁场景的另一半。

正确的解决方案是替换Resultawait,并将单元测试方法的返回类型从void更改为Task

于 2015-08-14T13:05:41.347 回答
-2

你的测试坏了。

xUnit 需要Task返回才能确定测试失败,更重要的是,它是异常冒泡返回到 xUnit 的句柄。

通过拥有public async void,您就有了一个异常的孤儿Task。由此产生的异常当然不会被处理,因此当然会炸毁整个流程。因此您的测试运行停止。

您可以通过像这样编写所有测试来修复它......

[Fact]
public async Task AmIAliveTest()
{
   var server = TestServer.Create<Startup>();

   var httpClient = server.HttpClient;
   var response = await httpClient.GetAsync("/api/status");

   response.StatusCode.Should().Be(HttpStatusCode.OK);
   var resultString = await response.Content.ReadAsAsync<string>();

   resultString.Should().Be("I am alive!");
}
于 2015-08-14T08:56:14.637 回答