我正在寻找有关该主题的一般想法和/或链接,尽管我目前的具体动机是使用 BackgroundWorker 和/或 TPL 与进度报告相关的 UI 任务。我对异步编程的经验一般是新手。我最了解的测试工具是 NUnit 和 Rhino。
一些头脑风暴的想法从我的脑海中浮现:
- 不要打扰 - 它太复杂了,你只需要测试 BGW 或 TPL。
- 做一些假的或模拟的。
- 使用 EventWaitHandles
我正在寻找有关该主题的一般想法和/或链接,尽管我目前的具体动机是使用 BackgroundWorker 和/或 TPL 与进度报告相关的 UI 任务。我对异步编程的经验一般是新手。我最了解的测试工具是 NUnit 和 Rhino。
一些头脑风暴的想法从我的脑海中浮现:
Unit testing asynchronous code is not the simplest thing in the world, as I learned when writing unit tests for my Nito.Async library. :)
First, you want to define what you actually want to test. Do you just want to test whether the asynchronous action is performed, or do you want to ensure that your BGW/tasks are properly synchronizing their UI progress reporting?
Testing the action is pretty straightforward: just wait until the action is complete and then check for postconditions. (However, be aware that the BGW RunWorkerCompleted
will be raised on a ThreadPool
thread unless you give it a synchronization context like the example below).
Testing proper synchronization (e.g., that each piece of code is running on the correct thread) is more complex.
For each test you'll need to establish a synchronization context. This will be mocking the UI synchronization context. My Nito.Async library may help with that; it has an ActionThread
which is a separate thread that contains a synchronization context suitable for owning EAP components (e.g., BGW) and scheduling tasks (e.g., TaskScheduler.FromCurrentSynchronizationContext
).
It can be used like this (using an MSTest example):
[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.
}
}
I find Thread.CurrentThread.ManagedThreadId
and Thread.CurrentThread.IsThreadPoolThread
to be the easiest ways to check for proper synchronization. If your test code is run from within ActionThread.Do
, then it should synchronize its progress updates (and completion notification) to that ActionThread
.
A lot of the Nito.Async unit tests use ActionThread
in this manner, so you could look there for various examples.