Reputation: 633
I have a process that runs in a thread (used as a realtime signal analysis process). I want to feed that thread process a known input, and then test -- in jUnit -- that the output is correct. I have a callback listener that can notify me when the thread finishes processing the data and I can run assertions on the result successfully by registering the test case itself as a listener.
When those assertions fail, they do throw an exception. But that exception is not registered as a failure by jUnit, presumably because they are happening outside of a test method.
How do I structure my jUnit test so that the test fails correctly after the listener returns? Here's a simplified version of the code.
public class PitchDetectionTest extends TestCase
implements EngineRunCompleteListener() {
AudioData fixtureData;
PitchDetectionEngine pitchEngine;
public void setUp() {
fixtureData = <stuff to load audio data>;
}
public void testCorrectPitch() {
pitchEngine = new PitchEngine(fixtureData);
pitchEngine.setCompletionListener(this);
pitchEngine.start();
// delay termination long enough for the engine to complete
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
}
// gets called by the PitchEngine when it has finished processing all data in the
// fixtureData. This is the only method defined by interface
// EngineRunCompleteListener.
public void notifyEngineRunComplete() {
// The real code asserts things about the PitchEngine's results. When they fail,
// an exception is thrown that I can see in the console, but this unit test still
// shows as 'success' in the jUnit interface. What I want is to see
// testCorrectPitch() fail.
assertTrue(false);
}
}
public class PitchEngine () {
EngineRunCompleteListener completionListener();
Thread myThread;
public void start() {
// other stuff
myThread = new Thread(this);
myThread.start();
}
public void run() {
while (some condition) {
// do stuff with the data
}
if (engineRunCompleteListener != null) {
engineRunCompleteListener.notifyEngineRunComplete();
}
}
}
Upvotes: 15
Views: 16089
Reputation: 53694
if you must run the assertion code within the callback, wrap the callback method in a try catch. catch any throwable and have a way of passing that exception back to the junit thread (some sort of shared thread state). the junit thread then just re-throws any returned throwable.
Upvotes: 1
Reputation: 139921
I want to feed that thread process a known input, and then test -- in jUnit -- that the output is correct. I have a callback listener that can notify me when the thread finishes processing the data and I can run assertions on the result successfully by registering the test case itself as a listener.
Rather than starting a separate thread for PitchEngine
inside your unit test, why not extract the //do stuff with the data
logic in PitchEngine
to another public method and simply invoke that in the unit test? I can't think of any reason to actually spawn the thread inside your unit test, since it sounds like all you really care about (in this unit test) is testing the processing logic.
Upvotes: 1
Reputation: 10321
You already have two threads running. Your junit thread, and the process thread (started by myThread.start()
.
Off the top of my head, I can think of at least two options that you have, all of them involving moving the assertion away from notifyEngineRunComplete
. For example:
join
to wait for the process thread to finish, and then do your assertions (Javadoc here).Executor
and a Future
object. I think this would be the coolest solution if it works with your classes (Javadoc here).Upvotes: 11