views:

256

answers:

5

This post started out as "What are some common patterns in unit testing multi-threaded code ?", but I found some other discussions on 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.

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.

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 ?

+3  A: 

you could use a recorder object that record the order, timings and other useful stuff in each unit test of your scheduler. The test is simple:

  1. create a recorder object
  2. configure the schedule
  3. execute a unit test
  4. check that recorder object is "compatible" with the schedule
dfa
This was the general direction of the thoughts I was having. Thank you for giving a name to the idea :). Is this a previously documented pattern? A quick google doesn't turn up any thing concrete.On the other hand Christian's suggestions of abstracting time are also interesting to explore ...
StudioEvoque
+2  A: 

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.

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.

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.

Christian Vest Hansen
+1  A: 

Have you had a look at the Quartz scheduler?

http://www.opensymphony.com/quartz/

Thorbjørn Ravn Andersen
Yep ! But long story about "official" open source library screening and certification coming soon ;)
StudioEvoque
+2  A: 

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.

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.

Kathy Van Stone
A: 

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)

If you are finding testing concurrency difficult consider refactoring your objects/components to make them easier to test.

Peter Lawrey