CurrentThreadTaskScheduler 未完成同步

2024-03-31

我尝试为视图模型编写单元测试,但在尝试验证 ICommand 调用异步方法两次时遇到了困难。

我使用 Moq 作为我的依赖项。 我像这样设置了异步方法。

this.communicationServiceFake
     .Setup(x => x.WriteParameterAsync(It.IsAny<string>(), It.IsAny<object>()))
     .ReturnsAsyncIncomplete();

扩展 ReturnsAsyncIncomplete 不会在 wait 关键字处立即返回,基本上类似于此处找到的内容:Async/Await 和代码覆盖率 http://bernhard-richter.blogspot.co.at/2014/09/asyncawait-and-code-coverage.html

我使用自己的 TaskSheduler 来确保方法在 Task.Factory.StartNew 返回之前完成。

Task.Factory.StartNew(() => viewModel.Command.Execute(null), 
    CancellationToken.None, TaskCreationOptions.None, new CurrentThreadTaskScheduler ());

基本上 CurrentThreadTaskScheduler 来自这里:等待单元测试中所有任务完成 https://stackoverflow.com/questions/17844182/wait-until-all-task-finish-in-unit-test看起来确实像这样:

public class CurrentThreadTaskScheduler : TaskScheduler
{
    protected override void QueueTask(Task task)
    {
        this.TryExecuteTask(task);
    }

    protected override bool TryExecuteTaskInline(Task task, bool wasPreviouslyQueued)
    {
        return this.TryExecuteTask(task);
    }

    protected override IEnumerable<Task> GetScheduledTasks()
    {
        yield break;
    }
}

该命令确实调用了以下代码:

await this.communicationService.WriteParameterAsync("Parameter1", true);
await this.communicationService.WriteParameterAsync("Parameter2", true);

然后验证:

  this.communicationServiceFake
       .Verify(t => t.WriteParameterAsync("Parameter1", true), Times.Once);
  this.communicationServiceFake
       .Verify(t => t.WriteParameterAsync("Parameter2", true), Times.Once);

有时它说第二个电话没有发生。 如果我用 ThreadSleep 替换我的 Task.Factory.StartNew 以确保一切都完成,那么即使不必要地延迟我的单元测试似乎是正确的,一切都可以正常工作。

为什么我的 CurrentThreadTaskScheduler 允许 Task.Factory.StartNew 在 Command.Execute 完成之前返回?


The GetIncompleteTask扩展方法在链接的博客文章 http://bernhard-richter.blogspot.co.at/2014/09/asyncawait-and-code-coverage.html uses Task.Run,因此引入了另一个线程(和竞争条件)。

The CurrentThreadTaskScheduler只会为async void方法(如果所有任务都已完成),这正是您所要做的avoiding with ReturnsAsyncIncomplete.

这是发生的事情:

  1. Execute跑进CurrentThreadTaskScheduler. It await正在线程池上运行的未完成任务。此时,StartNew任务完成。
  2. 线程池线程完成未完成的任务,并在current线程(线程池线程)。

你想要做的是单元测试async void完全覆盖的方法(即异步)。这当然不容易。

推荐解决方案

使用某种形式的async-aware ICommand比如我在中描述的我的 MSDN 文章 http://msdn.microsoft.com/en-us/magazine/dn630647.aspx。然后你就可以使用await viewModel.Command.ExecuteAsync(null)在你的单元测试中,不要乱搞自定义任务调度程序。

此外,异步模拟确实可以被简化;不需要自定义等待程序,因为 .NET 框架已经有一个:Task.Yield。因此,您可以用一个扩展方法(未经测试)替换所有代码:

public static IReturnsResult<TMock> ReturnsIncompleteAsync<TMock, TResult>(this IReturns<TMock, Task<TResult>> mock, TResult value) where TMock : class
{
  return mock.Returns(async () =>
  {
    await Task.Yield();
    return value;
  });
}

保持异步无效

如果你真的想保留现有的ICommand实现,并想要进行单元测试async void方法,and想要完整的代码覆盖率,那么你真的需要一个自定义的SynchronizationContext而不是自定义TaskScheduler。最简单的方法是安装我的AsyncEx NuGet 包 http://www.nuget.org/packages/Nito.AsyncEx并使用AsyncContext:

// Blocks the current thread until all continuations have completed.
AsyncContext.Run(() => viewModel.Command.Execute(null));

另外,我建议您使用Task.Yield上面描述的方法而不是线程池上的自定义等待。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CurrentThreadTaskScheduler 未完成同步 的相关文章

随机推荐

  • CUDA全局内存事务的成本

    根据 CUDA 5 0 编程指南 如果我同时使用 L1 和 L2 缓存 在 Fermi 或 Kepler 上 则所有全局内存操作都使用 128 字节内存事务完成 但是 如果我仅使用 L2 则使用 32 字节内存事务 第 F 4 2 章 让我
  • 建议在 C#.NET 中加密 XML 文件的最佳算法?

    我必须加密 XML 文件并通过网络发送到私人服务器中 我的另一个应用程序将通过提供实际的公钥来解密文件并将其导入到 SQL 你能建议我最好的方法吗 File XML类型 可能的尺寸 最大 250 MB 技术 C NET 2008 Use X
  • YUI 压缩机和 .NET 应用程序

    我想使用 YUI Compressor 原始版本 并将其用作典型 MS 构建过程 Visual Studio 2008 MSBuild 的一部分 有人对此有任何指导或想法吗 例如 合并到项目中的好方法 如何处理现有的 CSS 和 JS 引用
  • 尝试拟合 CrossValidator 对象时 DataBricks PySpark 出错

    首先 我是 DataBricks 和 PySpark 的新手 所以如果这是我没有看到的简单解决方案 我深表歉意 我的集群位于 DataBricks 运行时 9 1 LTS Spark 3 1 2 Scala 2 12 上 我正在研究一个 N
  • 在 Perl 中如何使用变量作为变量名?

    我需要在 perl 中实现以下目标 printmsg val1 msg1 if val1 printmsg val2 msg2 if val2 printmsg val3 msg3 if val3 printmsg val4 msg4 if
  • return 语句之前/期间的 C 分段错误

    我在 return 语句之前打印要返回的值 并告诉我的代码打印在函数调用之后立即返回的值 但是 在第一个打印语句之后和第二个打印语句之前 我遇到了分段错误 还值得注意的是 这种情况总是发生在第三次调用该函数时 从来没有第一次或第二次 也从来
  • 修改访客的捆绑属性

    我应该如何从访问者内部修改顶点的捆绑属性 我想使用对图进行子脚本化的简单方法 但传递给访问者的图参数是 const 因此编译器不允许更改 我可以在访问者中存储对图表的引用 但这看起来很奇怪 A visitor which identifie
  • 计算 Java 对象的值?

    我有一个用于存储项目的 Java 对象 public class PaymentDetailsItem private String name private String amount private int quantity priva
  • 在 Excel5.php 中找不到类“PHPExcel”

    我在 PHPExcel 中收到以下错误 Fatal error Class PHPExcel not found in PHPExcel Reader Excel5 php on line 587 这很奇怪 因为我在网上搜索时没有遇到过它
  • 尽管 rake 路线中有一条路线,但没有路线匹配

    我变得奇怪ActionController RoutingError No route matches 可以生成路线 gt r Rails application routes gt r generate controller items
  • 通用语言对 PCRE(Perl 兼容正则表达式)有哪些支持?

    我对 PCRE Perl 兼容正则表达式 的强大功能很感兴趣 并且想知道它们是否有可能成为所有主要语言中事实上的方法 我对 Java 感兴趣 如果有必要 我准备使用图书馆 我也无法在 SO 中找到一个很好的页面来描述 PCRE 的优缺点 因
  • Web 服务存根生成 + android

    我想生成一个基于 android java 的 STUB 来访问所有 Web 服务 我尝试使用以下工具生成存根 1 用于 CLDC 的 Sun Java TM 无线工具包 2 5 2 01 2 ksoap2 生成 stub 0 1 SNAP
  • 我可以使用特征稀疏矩阵来满足一般存储需求吗

    我需要一个模板化的稀疏矩阵实现 但只是为了减少内存占用 not进行任何数值求解 所以我尝试使用 Eigen 尽管我不需要数学部分 为什么 它恰好就在我的机器上 而且我已经用它来做其他事情了 但我肯定不是本征专家 Context 我有一个类型
  • 使用 LINQ 查询初始化 List

    我正在初始化一个List
  • Perl chomp 将多位数字变成 1 或 0

    我遇到一种情况 我需要用 Perl 读取一个充满数字的文件 这本身工作得很好 但是当我尝试删除每一行时 它会将以前的 5 或 6 位数字变成 1 或 0 Ideas 我需要对数字进行咀嚼以将文件路径与它们组合起来 因此回车符是一个问题 你没
  • 如何从 BroadcastReceiver 发出通知?

    如何从 BroadcastReceiver 发出通知 不能使用大多数方法 也不能使用 this 我需要它来打开一个包含数据库信息的活动我已经做到了 但现在必须的方法不起作用 我不能使用 这个 In the onReceive方法你得到一个C
  • LibGDX 将 BitmapFont 绘制到中间位置(spritebatch)

    我想使用 BitmapFont 绘制一些文本 临时位置 然后绘制该位置的一部分 到最后的精灵批次 我当时正在考虑画画 到临时 spritebatch 但不可能 将 spritebatch 绘制到另一个上 我怎样才能做到这一点 您可以使用帧缓
  • C - 返回指向局部变量的指针的函数

    考虑以下代码 include
  • Oracle 10g PL/SQL Connect By Prior 返回同一行上的子级和父级

    Table1 Child Parent a Bob Chris 2 Chris Kate 1 Shane Lana 3 Nala Bob 4 Table2 b Talent 1 something 2 nothing 3 something
  • CurrentThreadTaskScheduler 未完成同步

    我尝试为视图模型编写单元测试 但在尝试验证 ICommand 调用异步方法两次时遇到了困难 我使用 Moq 作为我的依赖项 我像这样设置了异步方法 this communicationServiceFake Setup x gt x Wri