Java – how to execute unit tests using threads?
Executive Summary: when an assertion error is thrown in the thread, the unit test will not crash This makes sense because one thread should not be allowed to crash another The problem is how to 1) fail the whole test when the first worker thread crashes or 2) loop and determine the complete state of each thread (see the code below) One way to execute the latter is by having each thread state variable, such as "Boolean [] state", and having "status [i] = = false" means that the thread fails (which can be extended to capture more information) But that's not what I want: I want to fail like any other unit test when an assertion error is thrown Is this even possible or desirable?
Bored, I decided to generate a bunch of threads in my unit test and let them call a service method just for its sake The code looks like this:
Thread[] threads = new Thread[MAX_THREADS]; for( int i = 0; i < threads.length; i++ ) { threads[i] = new Thread( new Runnable() { private final int ID = threadIdSequenceNumber++; public void run() { try { resultRefs[ID] = runTest( Integer.toString( ID ) ); // returns an object } catch( Throwable t ) { // this code is EVIL - it catches even // Errors - don't copy it - more on this below final String message = "error testing thread with id => " + ID; logger.debug( message,t ); throw new IllegalStateException( message,t ); // need to wrap throwable in a // run time exception so it will compile } } } ); }
After that, we will loop through the thread array and start each thread After that, we will wait for them to finish Finally, we'll do some checking on the result references
for( Thread thread : threads ) thread.start(); logger.debug( "waiting for threads to finish ..." ); boolean done = false; while( !done ) { done = true; for( Thread thread : threads ) if( thread.isAlive() ) done = false; } for( int i = 0; i < resultRefs.length; i++ ) { assertTrue( "you've got the world messed,dawg!",myCondition(resultRefs[i]) );
This is the problem Have you noticed the annoying try catch throwable block? I just added that as a temporary hacker, so I can see what happened In runtest (string), some assertions are made, such as assertNotNull (null), but because it is in different threads, it will not cause the unit test to fail!!!
My guess is that we need to traverse the thread array in some way, check the status of each thread, and manually raise an assertion error if the thread terminates in an annoying way The name of the method giving this information (stack trace of the dead thread)
Solution
Concurrency is one of the most difficult things in unit testing If you just try to test what the code in each thread is doing, maybe you should just test the code in this isolated context If threads cooperate to achieve a result in this example, you can test the collaboration without using threads This will be done by executing all collaborative parts in sequence If you want to test race conditions and these things, unit testing is not the best way You'll get tests that sometimes fail and sometimes don't In a word, I think your problem may be that your unit test level is too high I hope this can help