java 对调度程序进行单元测试的策略有哪些?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/931650/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What are some strategies to unit test a scheduler?
提问by StudioEvoque
This post started out as "What are some common patterns in unit testing multi-threaded code ?", but I found some otherdiscussionson SO that generally agreed that "It is Hard (TM)" and "It Depends (TM)". So I thought that reducing the scope of the question would be more useful.
这篇文章的开头是“单元测试多线程代码中的一些常见模式是什么?”,但我发现其他一些关于 SO 的讨论普遍同意“它很难 (TM)”和“它取决于 (TM)”。所以我认为缩小问题的范围会更有用。
Background: We are implementing a simple scheduler that gives you a way to register callbacks when starting and stopping jobs and of course configure the frequency of scheduling. Currently, we're making a lightweight wrapper around java.util.Timer.
背景:我们正在实现一个简单的调度程序,它为您提供了一种在启动和停止作业时注册回调的方法,当然还可以配置调度频率。目前,我们正在围绕 java.util.Timer 制作一个轻量级的包装器。
Aspects:
方面:
I haven't found a way to test this scheduler by relying on only public interfaces (something like
addJob(jobSchedule, jobArgs,jobListener),removeJob(jobId)).How do I time the fact that the the job was called according to the schedule specified ?
我还没有找到仅依赖公共接口(例如
addJob(jobSchedule, jobArgs,jobListener),removeJob(jobId))来测试此调度程序的方法。我如何根据指定的日程安排调用作业的时间?
采纳答案by dfa
you could use a recorder objectthat record the order, timings and other useful stuff in each unit test of your scheduler. The test is simple:
您可以使用记录器对象来记录调度程序的每个单元测试中的顺序、时间和其他有用的东西。测试很简单:
- create a recorder object
- configure the schedule
- execute a unit test
- check that recorder object is "compatible" with the schedule
- 创建记录器对象
- 配置时间表
- 执行单元测试
- 检查记录器对象是否与计划“兼容”
回答by Kathy Van Stone
One thing also to remember is that you don't need to test that Timer works. You can write a mock version of Timer (by extending the class or using EasyMock) that simply checks that you are calling it correctly, possibly even replacing enough that you don't need threads at all. In this case that might be more work than needed if your job listener has enough callbacks to track the scheduler.
还要记住的一件事是您不需要测试 Timer 是否有效。您可以编写 Timer 的模拟版本(通过扩展类或使用EasyMock)来简单地检查您是否正确调用了它,甚至可能替换掉足够多的线程以至于您根本不需要线程。在这种情况下,如果您的作业侦听器有足够的回调来跟踪调度程序,那么工作量可能会超出需要。
The other important thing to remember is that when testing the scheduler, use custom jobs that track how the scheduler is working; when testing scheduled jobs, call the callbacks directly and not through the scheduler. You may have a higher level integration test that checks both together, depending on the system.
另一个要记住的重要事情是,在测试调度程序时,使用跟踪调度程序工作方式的自定义作业;在测试预定作业时,直接调用回调而不是通过调度程序。根据系统,您可能有一个更高级别的集成测试来同时检查两者。
回答by Chris Vest
There are many failure modes that such a scheduler could exhibit, and each would most likely require its own test case. These test cases are likely to be very different, so "it depends."
这样的调度程序可能会表现出许多失败模式,并且每种模式很可能都需要自己的测试用例。这些测试用例可能非常不同,因此“视情况而定”。
For testing concurrent software in Java in general, I recommend this presentation from JavaOne 2007: Testing Concurrent Software.
为了测试 Java 中的并发软件,我推荐 JavaOne 2007 中的这个演示文稿:Testing Concurrent Software。
For testing that a scheduler must execute jobs in accurate accordance to their schedule, I'd create an abstraction of time itself. I've done something similar in one of my projects, where I have a Time or Clock interface. The default implementation will be MillisecondTime, but during testing I will switch it out with a TickTime. This implementation will allow my unit test to control when the time advances and by how much.
为了测试调度程序必须准确地按照他们的时间表执行作业,我会创建一个时间本身的抽象。我在我的一个项目中做了类似的事情,我有一个时间或时钟界面。默认实现将是 MillisecondTime,但在测试期间,我将使用 TickTime 将其关闭。此实现将允许我的单元测试控制时间何时提前以及提前多少。
This way, you could write a test where a job is scheduled to run once every 10 tick. Then your test just advances the tick counter and checks to make sure that the jobs run at the correct ticks.
这样,您可以编写一个测试,其中计划每 10 个滴答运行一次作业。然后您的测试只是推进滴答计数器并检查以确保作业以正确的滴答运行。
回答by Peter Lawrey
A couple of ways to test concurrent code.
测试并发代码的几种方法。
- run the same code many times under load, some bugs appear only occasionally, but can show up consistently if performed repeatedly.
- Store the results of different threads/jobs in a collection such as a BlockingQueue. This will allow you to check the results in the current thread and finish in a timely manner (without ugly arbitrary sleep statements)
- 在负载下多次运行相同的代码,一些错误只是偶尔出现,但如果重复执行,则可以始终如一地出现。
- 将不同线程/作业的结果存储在一个集合中,例如 BlockingQueue。这将允许您检查当前线程中的结果并及时完成(没有丑陋的任意睡眠语句)
If you are finding testing concurrency difficult consider refactoring your objects/components to make them easier to test.
如果您发现测试并发性很困难,请考虑重构您的对象/组件以使其更易于测试。
回答by Raedwald
If the scheduler delegates to an Executoror ExecutorServiceto run the tasks, you could use Dependency Injection to remove a direct dependency on the type of Executor, and use a simple single threaded Executorto test much of the functionality of your scheduler withoutthe complication of truly multi-threaded code. Once you'd got those tests debugged, you could move on the the harder, but now substantially reduced in magnitude, task of testing thread-safety.
如果调度程序委托给Executor或ExecutorService运行任务,您可以使用依赖注入来消除对 类型的直接依赖Executor,并使用简单的单线程Executor来测试调度程序的大部分功能,而无需真正多线程的复杂性代码。一旦你调试了这些测试,你就可以继续进行更难的测试,但现在测试线程安全的任务的数量已经大大减少了。

