我有一个方法,应该进行http调用,并且应该等待响应时间不超过某个超时时间。如果在超时时间内没有收到响应,方法应该返回空字符串。但是 响应必须在后面处理。
async Task<string> GetResponseOrContinue(int timeout, Action<string> responseHandler)
{
var task = Task.Run(async () =>
{
var response = await _webClient.UploadStringTaskAsync("url", "");
responseHandler(response);
return response;
});
var emptyTask = Task.Run(async () =>
{
await Task.Delay(timeout);
return string.Empty;
});
return await await Task.WhenAny(task, emptyTask);
}
为了简单起见,我省略了trycatches和其他细节......这段代码似乎可以工作,但我在尝试测试时卡住了。
我写的测试几乎总是正确的,但有时这个超时的东西出了问题,测试失败。
我模拟了 UploadStringTaskAsync
调用 Moq框架:
certWebClient.Setup(x => x.UploadStringTaskAsync(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(() =>
{
Thread.Sleep(timeout + 10);
return "this response will be received after timeout";
});
然后通过这个 超时 变量到 GetResponseOrContinue
的方法。看上去很简单,但不值得信任......这里会出什么问题,也许有更合适的解决这种问题的方法?
单元测试这种代码的一个方法是抽象掉所有与线程、任务、定时器、日期等有关的东西。例如,你可以注入一个特殊的task-factory,它可以返回可能由你的测试明确完成的任务。
这使得代码和测试的编写都变得更加复杂。所以我会考虑任何特殊测试的成本效益。