Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to jUnit test the result of code in another thread

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();
    }
  }

}
like image 982
IdahoEv Avatar asked Apr 03 '11 18:04

IdahoEv


People also ask

How do I test a concurrent code?

One good way to test this is to make sure you have access to a multi-cpu machine, then run your test for as long a time/with as many iterations as possible. For example if you have a multithreaded producer consumer algorithm, fill the queue with a good sized list and use 2x as many threads as you might in production.

Is JUnit multithreaded?

Concurrent-junit library helps the users to test the methods for multi threading. It will create threads for testing methods. By default, number of threads created by this library is 4, but we can set the desired number of threads.

Do JUnit tests run sequentially?

1. Overview. By default, JUnit runs tests using a deterministic but unpredictable order (MethodSorters.


3 Answers

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:

  • You can use join to wait for the process thread to finish, and then do your assertions (Javadoc here).
  • You can put your junit thread to sleep by waiting on a monitor object, and then in your callback function notify this monitor. This way you'll know that the process has finished.
  • You can use an Executor and a Future object. I think this would be the coolest solution if it works with your classes (Javadoc here).
like image 56
Yoni Avatar answered Oct 07 '22 16:10

Yoni


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.

like image 1
matt b Avatar answered Oct 07 '22 16:10

matt b


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.

like image 1
jtahlborn Avatar answered Oct 07 '22 17:10

jtahlborn