Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

junit assert in thread throws exception

Tags:

What am I doing wrong that an exception is thrown instead of showing a failure, or should I not have assertions inside threads?

 @Test  public void testComplex() throws InterruptedException {   int loops = 10;   for (int i = 0; i < loops; i++) {    final int j = i;    new Thread() {     @Override     public void run() {      ApiProxy.setEnvironmentForCurrentThread(env);//ignore this      new CounterFactory().getCounter("test").increment();//ignore this too      int count2 = new CounterFactory().getCounter("test").getCount();//ignore      assertEquals(j, count2);//here be exceptions thrown. this is line 75     }    }.start();   }   Thread.sleep(5 * 1000);   assertEquals(loops, new CounterFactory().getCounter("test").getCount()); } 

StackTrace

Exception in thread "Thread-26" junit.framework.AssertionFailedError: expected:<5> but was:<6>     at junit.framework.Assert.fail(Assert.java:47)     at junit.framework.Assert.failNotEquals(Assert.java:277)     at junit.framework.Assert.assertEquals(Assert.java:64)     at junit.framework.Assert.assertEquals(Assert.java:195)     at junit.framework.Assert.assertEquals(Assert.java:201)     at com.bitdual.server.dao.ShardedCounterTest$3.run(ShardedCounterTest.java:77) 
like image 516
antony.trupe Avatar asked Apr 07 '10 23:04

antony.trupe


1 Answers

The JUnit framework captures only assertion errors in the main thread running the test. It is not aware of exceptions from within new spawn threads. In order to do it right, you should communicate the thread's termination state to the main thread. You should synchronize the threads correctly, and use some kind of shared variable to indicate the nested thread's outcome.

EDIT:

Here is a generic solution that can help:

class AsynchTester{     private Thread thread;     private AssertionError exc;       public AsynchTester(final Runnable runnable){         thread = new Thread(new Runnable(){             public void run(){                 try{                                 runnable.run();                 }catch(AssertionError e){                     exc = e;                 }             }         });     }      public void start(){         thread.start();     }      public void test() throws InterruptedException{         thread.join();         if (exc != null)             throw exc;     } } 

You should pass it the runnable in the constructor, and then you simply call start() to activate, and test() to validate. The test method will wait if necessary, and will throw the assertion error in the main thread's context.

like image 117
Eyal Schneider Avatar answered Sep 18 '22 13:09

Eyal Schneider