October 1, 2004 12:00 AM

OOPSLA'04: Mock Object Presentation and jMock Demo

I'm currently at OOPSLA in Vancouver. Steve Freeman and myself gave a presentation on using Mock Objects to guide the design of good object-oriented code and a demo of jMock.

The presentation did not go that well. We only had 20 minutes to talk and with that little time could not really show anything in action. Instead we gave a hand-wavy presentation with a made up example application based on a tea shop. I think the example was too artificial and the talk too high level to really show the techniques in action. Joe and I had the same problem with our example when we gave a mock objects demo at OT2004. The format of the presentation was uncomfortable for me too: I was stuck behind a fixed mike but I much prefer to walk around the stage and gesticulate like a loon engage the audience.

The demo went much better. We fired up the IDE and ran a few TDD iterations using mock objects to explore the design of some objects in our tea shop example. I think showing the library in action when coding really helped get some of our ideas about the larger process across to the audience. Also, I had a clip on mike and the audience was smaller, so I could adopt a more dynamic style and interact directly with the audience. It was great to meet some happy jMock users after the demo and chat with them about their experience with the library. However, the tea shop example was not perfect and served to confuse the message a little.

Duncan Pierce has had a lot of success using video games as example domains when teaching programming and design techniques. I always write a video game whenever I learn a new language or platform because a reasonably entertaining game exercises a lot of different features: event handling, graphics, distribution, file I/O, timing, etc. etc. Perhaps a video game would work much better as a demo for jMock. After all, it was a commercial video game project that drove me to write the forerunner of jMock and experience on that project, among others, informed the design of the current jMock API.

Posted on October 28, 2004 [ Permalink ]

Testing Multithreaded Code with Mock Objects

knot.jpg

A question that is frequently asked on the jMock users' mailing list is "how do I use mock objects to test a class that spawns new threads"? The problem is that jMock appears to ignore unexpected calls if they are made on a different thread than that which runs the test itself. The mock object actually does throw an AssertionFailedError when it receives an unexpected call, but the error terminates the concurrent thread instead of the test runner's thread.

Here's a far-fetched example. We have a guard and an alarm. When the guard gets bored, he shouldn't ring the alarm just for kicks.

public interface Alarm {
	void ring();
}

public class testGuardDoesNotRingTheAlarmWhenHeGetsBored() {
	Mock mockAlarm = mock(Alarm.class);
	Guard guard = new Guard( (Alarm)alarm.proxy() );
	
	guard.getBored();
}

Here's an implementation of Guard that should fail the test:

public class Guard {
	private Alarm alarm;
	
	public Guard( Alarm alarm ) {
		this.alarm = alarm;
	}
	
	public void getBored() {
		startRingingTheAlarm();
	}
	
	private void startRingingTheAlarm() {
		Runnable ringAlarmTask = new Runnable() {
			public void run() {
				alarm.ring();
			}
		};
		
		Thread ringAlarmThread = new Thread(ringAlarmTask);
		ringAlarmThread.start();
	}
}

However, the test will pass because the mock Alarm will throw an AssertionFailedError on the ringAlarmThread, not the test runner's thread.

The root of the problem is trying to use mock objects for integration testing. Mock objects are used for unit testing in the traditional sense: to test units in isolation from other parts of the system. Threads, however, by their very nature, require some kind of integration test. Concurrency and synchronisation are system-wide concerns and code that creates threads must make use of operating system facilities to do so.

A solution is to separate the object that needs to run tasks from the details of how tasks are run and define an interface between the two. We can test the object that needs to run tasks by mocking the task runner, and test the implementation of the task runner in integration tests.

In our running example, we can introduce a TaskRunner interface to which the Guard passes tasks that it wants to run instead of explicitly creating new threads.

public interface TaskRunner {
	void start( Runnable task );
}

Our test then looks like:

public class testGuardDoesNotRingTheAlarmWhenHeGetsBored() {
	Mock mockAlarm = mock(Alarm.class);
	TaskRunner taskRunner = ... // What goes here?
	Guard guard = new Guard( (Alarm)alarm.proxy(), taskRunner );
	
	guard.getBored();
}

But how should we implement the TaskRunner that we use in our test? If we pass in a TaskRunner that creates a new thread we'll be back where we started and our tests will still, wrongly, appear to pass. We need to run the task in the same thread as the test runner. The easiest way to do that is to run the task immediately it is started, without spawning a thread at all. To do this we could mock the TaskRunner interface and use a custom stub to call back to the task's run method, but that's over-complicating things. It's much easier just to write a class that implements the interface:

public class ImmediateTaskRunner implements TaskRunner {
	public void start( Runnable task ) {
		task.run();
	}
}

Our test then looks like:

public class testGuardDoesNotRingTheAlarmWhenHeGetsBored() {
	Mock mockAlarm = mock(Alarm.class);
	TaskRunner taskRunner = new ImmediateTaskRunner();
	Guard guard = new Guard( (Alarm)alarm.proxy(), taskRunner );
	
	guard.getBored();
}

And the implementation of the Guard and the task runner it uses look like this:

public class Guard {
	private Alarm alarm;
	private TaskRunner taskRunner;
	
	public Guard( Alarm alarm, TaskRunner taskRunner ) {
		this.alarm = alarm;
		this.taskRunner = taskRunner;
	}
	
	public void getBored() {
		startRingingTheAlarm();
	}
	
	private void startRingingTheAlarm() {
		Runnable ringAlarmTask = new Runnable() {
			public void run() {
				alarm.ring();
			}
		};
		
		taskRunner.start(ringAlarmTask);
	}
}

public class ConcurrentTaskRunner implements TaskRunner {
	public void start( Runnable task ) {
		(new Thread(task)).start();
	}
}

Another solution for unit testing would be to run the task in the test runner's thread after the call to guard.getBored() has finished. This might be useful if the Guard class contains try...finally statements that mask test failures caused by the task. Again, we can create a TaskRunner implementation to do this:

public class DelayedTaskRunner implements TaskRunner {
	private List delayedTasks = new ArrayList();

	public void start( Runnable task ) {
		delayedTasks.add(task);
	}
	
	public void runTasks() {
		for (Iterator i = delayedTasks.iterator(); i.hasNext(); ) {
			((Runnable)i.next()).run();
			i.remove();
		}
	}
}

public void testGuardDoesNotRingTheAlarmWhenHeGetsBored
	Mock mockAlarm = mock(Alarm.class);
	DelayedTaskRunner taskRunner = new DelayedTaskRunner();
	Guard guard = new Guard( (Alarm)alarm.proxy(), taskRunner );
	
	guard.getBored();
	taskRunner.runTasks();	
}

Pulling the mechanism for running tasks out of the object that needs tasks to be run can have other benefits beyond easier unit testing. One of the effects that Tim Mackinnon discovered on introducing mock objects into a project was that being forced to test classes in isolation creates "flex points" in the code that, spookily, are exactly where you need them as you evolve the codebase. For example, it would now be trivial to make our Guards use a shared thread pool instead of a ConcurrentTaskRunner.

Update: Doug Lea's concurrency library, which is now part of the Java 1.5 standard library, provides an Executor interface and various implementations.

Posted on October 14, 2004 [ Permalink | Comments (5) ]