C# 测试驱动异步任务

C# 测试驱动异步任务,c#,unit-testing,asynchronous,task-parallel-library,async-await,C#,Unit Testing,Asynchronous,Task Parallel Library,Async Await,我正在寻找关于这个主题的一般想法和/或链接,尽管我目前的具体动机是与使用BackgroundWorker和/或TPL的进度报告相关的UI任务。我的异步编程经验一般是新手。我最熟悉的测试工具是NUnit和Rhino 我脑子里突然闪现出一些想法: 不用麻烦了,这太复杂了,你只需要测试BGW或TPL就可以了 做一些假货或嘲弄 使用EventWaitHandles 单元测试异步代码并不是世界上最简单的事情,正如我在为我的库编写单元测试时所了解的那样: 首先,您需要定义您实际想要测试的内容。您只是想测试是

我正在寻找关于这个主题的一般想法和/或链接,尽管我目前的具体动机是与使用BackgroundWorker和/或TPL的进度报告相关的UI任务。我的异步编程经验一般是新手。我最熟悉的测试工具是NUnit和Rhino

我脑子里突然闪现出一些想法:

  • 不用麻烦了,这太复杂了,你只需要测试BGW或TPL就可以了
  • 做一些假货或嘲弄
  • 使用EventWaitHandles

  • 单元测试异步代码并不是世界上最简单的事情,正如我在为我的库编写单元测试时所了解的那样:

    首先,您需要定义您实际想要测试的内容。您只是想测试是否执行了异步操作,还是想确保BGW/任务正确同步其UI进度报告

    测试操作非常简单:只需等待操作完成,然后检查后置条件。(但是,请注意,BGW
    RunWorkerCompleted
    将在
    ThreadPool
    线程上引发,除非您像下面的示例那样为其提供同步上下文)

    测试正确的同步(例如,每段代码都在正确的线程上运行)更加复杂

    对于每个测试,您都需要建立一个同步上下文。这将模拟UI同步上下文。我的Nito.Async库可能会对此有所帮助;它有一个
    ActionThread
    ,它是一个单独的线程,包含一个适合拥有EAP组件(例如BGW)和调度任务(例如
    TaskScheduler.FromCurrentSynchronizationContext
    )的同步上下文

    它可以这样使用(使用MSTest示例):

    我发现
    Thread.CurrentThread.ManagedThreadId
    Thread.CurrentThread.IsThreadPoolThread
    是检查正确同步的最简单方法。如果测试代码是从
    ActionThread.Do
    中运行的,那么它应该将其进度更新(和完成通知)同步到该
    ActionThread


    很多Nito.Async单元测试都以这种方式使用
    ActionThread
    ,所以您可以在那里查找各种示例。

    您能更具体一点吗?也许发布一些代码,这样我们就可以看到你的代码是如何构造的,并相应地回答…@BFree。是的,这个问题很敏感,因此可能太模糊了,但我现在的任何代码都不适合简短的帖子或快速的回答。例如,如果问题是关于开始使用mocks,也许有人会建议Rhino和wiki一起使用,也许还有一篇关于开始使用它的好博文,以及他们自己经验中的一些技巧。干杯!这就是我要说的!我想你写这篇文章是为了让异步的生活变得更简单,没有真正的替代方案。下载中是否包含您的测试?一个人必须对第三方物流有多了解才能理解你的代码?我现在正在看你的博客。例如,在博客上查看ProgressReporter代码,以及如何在不需要制作win表单或其他ui项目的情况下对其进行测试。好东西!!该库最初是为了帮助编写EAP组件而编写的。但是,请注意,VS的未来方向(如VS异步CTP所示)引入了TAP,它将(我希望)取代EAP。因此,Nito.Async的某些部分在几年内将不再适用。不过,它仍然有几个有用的组件,例如
    ActionThread
    。该类有两个用途:允许Console/Windows服务程序具有同步上下文;并使我的单元测试更容易编写。:)单元测试包含在源代码中。异步目前没有使用任何TPL。TPL设计得非常好,不需要像Nito.Async在.NET4.0之前的版本那样的“填补空白”库。EAP=;TAP=基于任务的异步模式。
    [TestMethod]
    public void Test()
    {
      using (ActionThread thread = new ActionThread())
      {
        thread.Start();
    
        // Anything passed to Do is executed in that ActionThread.
        thread.Do(() =>
        {
          // Create BGW or call TaskScheduler.FromCurrentSynchronizationContext.
        });
    
        // The thread is gracefully exited at the end of the using block.
      }
    }