views:

838

answers:

3

I have Swing java application with network communications to several "Players" that are represented as player objects, each with their own communication thread. The app has a "Team" object managing all player objects. Several UI components listen to events passed from the players through the Team object.

In my design, the team object fires all events on the Swing thread using invokeLater, so that the rest of my application does not need to bother with threading issues. However, I don't know how I can test the Team class in a JUnit test.

A little more background. At first I had the Team object fire its events on the player object threads (no thread switching at all). The Team unit test succeeded, but I got into many threading issues in my UI with invokeLaters and synchronized all over the place. I then decided to simplify the threading model by having the Team object fire events on the Swing thread, but now the Team unit test fails because it does not receive the events. What to do?

A solution that comes to mind is to introduce an extra object on top of Team that does the thread switch and keep the original unit test intact, but I do not like the idea of introducing complexity in production code just to make a unit test succeed.

+1  A: 

Maybe you can use easymock to isolate the classes you want to test, and have the mock objects receive the events and check that they're fired.

I'd recommend EasyMock: http://www.easymock.org/

From your story it feels that your unittests are more integration tests, and very intricate. If that's the case, try to simplify and isolate. You've probably read http://junit.sourceforge.net/doc/testinfected/testing.htm

I hope this helps.

Rolf
You are right that I test more than a single class. What I try to achieve is to verify that the communication between several processes works up to the team level. It is the interaction between the object I want to test, and I'll need to think to find another way. Thanks for the advice.
Emile
+1  A: 

When I've done JUnit testing with EventQueue.invokeLater, I've decoupled myself from that evil static. Create an interface with invokeLater is isDispatchThread methods. For production the implementation should just forward to EventQueue. For testing, use your own thread (which can be set up and torn down for each test).

Some other random advice:

  • Keep the GUI as thin as possible.
  • Keep threading out of everything else, and everything else out of threading.
  • Be suspicious of anything claiming to be thread-safe.
Tom Hawtin - tackline
I like your advice, especially the second. Your suggestion to introduce an interface is probably the way to go. Still, I feel a little uncomfortable that I have to do this "just" to test something.
Emile
+1  A: 

A solution that comes to mind is to introduce an extra object on top of Team that does the thread switch and keep the original unit test intact, but I do not like the idea of introducing complexity in production code just to make a unit test succeed.

I don't know if this is the case here but I often find that the "complexity" that I'm adding is actually a higher level of abstraction that improves the code.

The original idea behind mock objects wasn't to make unit testing easier but rather "interface discovery", to create interfaces that represent the abstractions in your ubiquitous language rather than working at the level of the API.

Jeffrey Fredrick
I agree on complexity and functional abstraction, but in this case I am dealing "only" with threading issues that can pretty easy be solved by doing most things on the UI thread, except that this makes the testing more difficult. Thanks for getting me rethink on my abstractions!
Emile