gpt4 book ai didi

c# - 异步任务测试

转载 作者:太空宇宙 更新时间:2023-11-03 23:41:28 26 4
gpt4 key购买 nike

我刚开始使用 Rhino Mocks 在代码中测试我的异步方法。但是,虽然通常代码可以完美运行,但在使用 Rhino Mocks 进行模拟测试时,会出现一些奇怪的 async 问题。

假设我想测试以下调用多个 numberGenerators 的代码,它们将同时运行并等待它们全部完成:

public async Task MyTask()
{
List<Task<List<int>>> numberTasks = new List<Task<List<int>>>();

foreach (var numberGenerator in numberGenerators)
{
// GetNumbers is an 'async Task<List<int>>'
// As you can see I don't use 'await' so it should just add it and go on.
numberTasks.Add(numberGenerator.GetNumbers());
}

try
{
await Task.WhenAll(numberTasks);
}
catch (Exception e)
{
// Log exception if something happens at 'GetNumbers' (like time-out or whatever)
}

var numbers = new List<int>();
numbers.AddRange(numberTasks.Where(task => task.Status == TaskStatus.RanToCompletion).SelectMany(task => task.Result));

// Do something with the numbers
}

测试:

numberGenerator.Expect(x => x.GetNumbers())
.WhenCalled(x => Thread.Sleep(10000))
.Return(Task.FromResult(numbers));

在上面的代码中,我在“mocked”上使用了两个生成器。现在,如果我使用“非模拟”对象运行代码 numberTasks.Add 只需添加任务并继续。但是当我用 WhenCalled sleep 模拟它时,它会等待 10 秒,然后再转到 foreach 循环中的下一个。

我如何更改我的 mock,让它像普通的 async Task 一样需要 10 秒才能完成?

奖励问题:我希望能够对 .Throw() 做同样的事情,这样我就可以在抛出异常之前等待 10 秒。

更新:尽管我认为以下内容可以解决问题:

numberGenerator.Expect(x => x.GetNumbers())
.Return(Task.Delay(10000).ContinueWith(x => numbers));

好像不是这样的。创建此 mock 时,Task.Delay 开始倒计时。因此,如果我创建此模拟,请等待 10 秒,然后运行测试,它将在 0 秒内完成。

所以我的问题仍然存在,如何在返回结果之前使用 delay 测试异步方法。

最佳答案

异步方法同步运行,直到到达 await。这意味着如果您在模拟操作中返回任务之前等待,则此等待将是同步的。您想要做的是立即返回一个在一段时间后完成的任务。

你可以用 Task.Delay 来做到这一点:

numberGenerator.Expect(x => x.GetNumbers()).
Return(Task.Delay(10000).ContinueWith(t => numbers));

Task.ContinueWith用于延迟完成后添加实际返回值。

如果你想抛出一个异常而不是返回一个值,那也可以在延续中完成。

由于 Task.Delay(10000).ContinueWith(t => numbers) 在创建模拟时被评估,每次调用将返回相同的任务(将在模拟后 10 秒完成被创建)。

如果每次都需要创建一个新任务,需要传递一个delegate。 Return 不接受委托(delegate),因此您需要使用 WhenCalled:

numberGenerator.Expect(x => x.GetNumbers()).
WhenCalled(mi => mi.ReturnValue = Task.Delay(10000).ContinueWith(x => numbers));

现在,虽然 WhenCalled 用于使用 Return 设置返回值,但仍然需要 in order to determine the type of the return result .它获得什么值并不重要,因为返回值仍将由 WhenCalled 设置:

numberGenerator.Expect(x => x.GetNumbers()).
WhenCalled(mi => mi.ReturnValue = Task.Delay(10000).ContinueWith(x => numbers)).
Return(Task.FromResult(new List<int>()));

关于c# - 异步任务测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28901009/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com