如何对任务同步运行进行单元测试

问题描述 投票:0回答:1

在我的代码中,我有一个方法,例如:

void PerformWork(List<Item> items)
{
    HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
    {
        foreach (var item in items)
        {
            await itemHandler.PerformIndividualWork(item);
        }
    });
}

Item只是一个已知模型,而itemHandler只是根据模型进行一些工作(ItemHandler类在单独维护的代码库中定义为nuget pkg,我不想修改)。此代码的目的是在后台同时同步处理列表中的项目。

作为工作的一部分,我想创建一个单元测试,以验证调用此方法时,项目是同步处理的。我很确定这个问题可以简化为:

await MyTask(1);
await MyTask(2);
Assert.IsTrue(/* MyTask with arg 1 was completed before MyTask with arg 2 */);

此代码的第一部分我可以轻松地进行单元测试,即保持了序列。例如,使用NSubstitute,我可以检查库代码上的方法调用顺序:

Received.InOrder(() =>
{
    itemHandler.PerformIndividualWork(Arg.Is<Item>(arg => arg.Name == "First item"));
    itemHandler.PerformIndividualWork(Arg.Is<Item>(arg => arg.Name == "Second item"));
    itemHandler.PerformIndividualWork(Arg.Is<Item>(arg => arg.Name == "Third item"));
});

但是我不太确定如何确保它们不会并行运行。我有几个想法似乎很糟糕,例如嘲笑库,使在调用PerformIndividualWork时出现人为延迟,然后检查正在排队的整个后台任务的时间,或者检查itemHandler接收到的调用的时间戳通话之间的最短时间。例如,如果我模拟了PerformIndividualWork来延迟500毫秒,并且我期望有3个项目,那么我可以检查经过的时间:

stopwatch.Start();
// I have an interface instead of directly calling HostingEnvironment, so I can access the task being queued here
backgroundTask.Invoke(...);
stopwatch.Stop();

Assert.IsTrue(stopwatch.ElapsedMilliseconds > 1500);

但是那感觉不正确,可能会导致误报。解决的办法可能在于修改代码本身。但是,我想不出一种有意义地更改它的方法,以使这种单元测试(测试任务按顺序运行)成为可能。我们肯定会进行系统/集成测试,以确保不会发生由单个项目的异步性能引起的问题,但是我也想在此级别进行测试。

c# unit-testing task nunit nsubstitute
1个回答
0
投票

[不确定这是否是一个好主意,但是一种方法可能是使用itemHandler来检测何时并行处理项目。这是一个简单又肮脏的例子:

© www.soinside.com 2019 - 2024. All rights reserved.