如何使用 TPL 和 TaskScheduler 编写单元测试
想象一下这样的函数:
private static ConcurrentList<object> list = new ConcurrentList<object>();
public void Add(object x)
{
Task.Factory.StartNew(() =>
{
list.Add(x);
}
}
我不关心 fentry 何时添加到列表中,但我需要将它添加到最后(显然;))
我没有找到一种方法来正确地对这样的东西进行单元测试而不需要返回任何回调处理程序或某物。因此添加程序不需要的逻辑
你会怎么做?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
实现此目的的一种方法是使您的类型可配置,使其采用
TaskScheduler
实例。现在,在单元测试中,您可以创建一个可测试的
TaskScheduler
版本。这是一个被设计为可配置的抽象类。简单地让计划函数将项目添加到队列中,然后添加一个函数来“立即”手动执行所有队列项目。然后您的单元测试可能类似于TestableScehduler
的示例实现One way to do this is to make your type configurable such that it takes a
TaskScheduler
instance.Now in your unit tests what you can do is create a testable version of
TaskScheduler
. This is an abstract class which is designed to be configurable. Simple have the schedule function add the items into a queue and then add a function to manually do all of the queue items "now". Then your unit test can look like thisExample implementation of
TestableScehduler
对我有用的解决方案是将 TaskScheduler 作为我想要进行单元测试的代码的依赖项发送(例如,
其中 asyncScheduler 用于调度在工作线程上运行的任务(阻止调用),而 guiScheduler 用于调度应运行的任务在 GUI 上(非阻塞调用),
然后在单元测试中,我将注入特定的调度程序,即 CurrentThreadTaskScheduler 实例。
CurrentThreadTaskScheduler 是一个调度程序实现,它立即运行任务,而不是对它们进行排队。
您可以在此处的 Microsoft 并行编程示例中找到实现。
我将粘贴代码以供快速参考:
The solution that worked for me was to send the TaskScheduler as a dependency to the code I want to unit test (e.g.
Where asyncScheduler is used to schedule tasks that run on worker threads (blocking calls) and guiScheduler is used to schedule tasks that should run on GUI (non blocking calls).
In the unit test, I would then inject a specific schedulers, i.e. CurrentThreadTaskScheduler instances.
CurrentThreadTaskScheduler is a scheduler implementation that runs the tasks immediately, instead of queuing them.
You can find the implementation in the Microsoft Samples for Parallel Programming here.
I'll paste the code for quick reference:
我和我的一位同事正在构建一个单元测试框架,它解决了 TPL 和 Rx 测试的问题,并且有您可以利用一个类来替换测试场景中的默认 TaskScheduler,这样您就不需要修改方法签名。该项目本身尚未发布,但您仍然可以在此处浏览该文件:
https://github.com/Testeroids/Testeroids/blob/master/solution/src/app/Testeroids/TplTestPlatformHelper.cs
设置任务调度程序的工作是在TplContextAspectAttribute.cs。
A colleague of mine and I are building a unit testing framework which addresses TPL and Rx testing, and there is a class which you could leverage to replace the default TaskScheduler in a testing scenario, so that you don't need to modify your method signatures. The project itself isn't published yet, but you can browse the file here nonetheless:
https://github.com/Testeroids/Testeroids/blob/master/solution/src/app/Testeroids/TplTestPlatformHelper.cs
The work of setting up the task scheduler is done in TplContextAspectAttribute.cs.
为列表创建一个公共财产怎么样?
或者在调试构建时将其设为公共字段:
What about making a public property for the list?
or maybe make it a public field when in DEBUG build:
至少对于大多数简单的情况,我喜欢对此类事情使用“过期”断言。例如:
其中
EventualAssert.IsTrue()
看起来像这样:我通常还会添加一个具有默认超时的覆盖,我将其用于大多数测试,但是 ymmv.. 。
For at least most simple-ish cases, I like to use an "expiring" assertion for this sort of thing. e.g.:
where
EventualAssert.IsTrue()
looks something like this:I also generally add an override with a default timeout which I use for most of my tests, but ymmv...