18

When I test the execution of a method that creates a child thread, the JUnit test ends before the child thread and kills it.

How do I force JUnit to wait for the child thread to complete its execution?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Mark
  • 67,098
  • 47
  • 117
  • 162

6 Answers6

8

After reading the question and some comments, it seems that what you need is a technique for unit testing asynchronous operations. doSomething() returns immediately, but you want the test code to wait for its completion, and then do some validations.

The problem is that the test is not aware of the threads being spawned by the call, so apparently it has no means of waiting for them. One can think of many sophisticated (and probably flawed) ways to solve this, but in my opinion there is a design problem here. A unit test should simulate a client of some API, and it should not assume anything about the implementation; It should only test functionality, as reflected by the API and its documentation. Therefore, I would avoid trying to detect and track the threads created by the async call. Instead, I would improve the API of the tested class, if needed. The class where the async call belongs to should provide some mechanism for detecting termination. I can think of 3 ways, but there are probably more:

  1. Allow registering a listener that gets notified once the operation is completed

  2. Providing a synchronous version of the operation. The implementation can call the async version, and then block until completion. If the class should not be exposing such a method, its visibility can be reduced to package protected, so that the test can access it.

  3. Using the wait-notify pattern, on some visible object.

If the class provides no such mechanism, then it is not really testable, and worse, it is probably not very reusable either.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Eyal Schneider
  • 22,166
  • 5
  • 47
  • 78
2

Try using thread.join() on the created thread. This will wait for that thread to die.

Edit: to avoid this, try Thread.getThreadGroup().setDaemon(true); in the test, or perhaps in the setUp() method. I haven't tested this though.

A daemon thread group is automatically destroyed when its last thread is stopped or its last thread group is destroyed.

I wonder if JUnit is calling System.exit() or something as soon as the test finishes, however.

beldaz
  • 4,299
  • 3
  • 43
  • 63
Chris Dennett
  • 22,412
  • 8
  • 58
  • 84
  • Actually I'd would avoid this solution, instead i was looking for a better way to run this kind of tests and force the main thread to wait for the end of its childs. – Mark May 14 '10 at 19:23
  • @Marco: can you please elaborate? what is wrong with Chris' solution? – Eyal Schneider May 14 '10 at 19:26
  • I'm testing a method doSomething() that internally starts some threads that update some db tables. What I'd like to do is to run this method inside my JUnit test and then check if all the edits on the database have been saved successfully. It's important for the method doSomething() to not join the threads when they're created, and so i can't adopt the join() solution. – Mark May 14 '10 at 19:30
  • I'd recommend creating a thread group, creating a new thread attaching it to that group and creating your new threads in that. After that, joining the created ThreadGroup, but ThreadGroup doesn't seem to have the join() method. Argh :) – Chris Dennett May 14 '10 at 19:32
  • You could always spin on activeCount() > 0 inside the test on that ThreadGroup (but would that capture child thread groups?). – Chris Dennett May 14 '10 at 19:33
  • Something a little strange here. How do you know when to test the database for created objects if you don't know when doSomething() has actually done something? Calling doSomething() and checking the results should be part of the same test, since unit tests are meant to be independent. To do this, you need some kind of synchronization - you have to wait for the work to be done before you can verify the results. It's not the test runner's job to wait, but your test code's responsibility. – mdma May 14 '10 at 23:15
1

The basic technique that Eyal Schneider outlined in his answer is what my ConcurrentUnit library is intended to accomplish. The general usage is:

  1. Spawn some threads
  2. Have the main thread wait or sleep
  3. Perform assertions from within the worker threads (which via ConcurrentUnit, are reported back to the main thread)
  4. Resume the main thread from one of the worker threads once all assertions are complete

See the README on GitHub for more info.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Jonathan
  • 5,027
  • 39
  • 48
0
        while (s.isRunning()) {
            try {
                Thread.sleep(SLEEP_TIME);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

You could try to block the JUnit thread and have it wait for your thread to complete. The Thread.sleep() is needed so that your thread does not hog CPU. In this example s would be your thread you will need to have an isRunning() method so you can check if the thread is still running every SLEEP_TIME milliseconds. I know this isn't the greatest solution but if you only have 2 threads and you dont want JUnit killing your thread this works. The while loop with cause this JUnit thread to stay alive and wait for your other thread to finish.

Szymon
  • 42,577
  • 16
  • 96
  • 114
Fred
  • 1
0

Perhaps group your threads with an ExecutorService, then use shutdown and awaitTermination method ?

The condition is to use Runnable or Future, not Threads themselves.

Istao
  • 7,425
  • 6
  • 32
  • 39
0

In java, try use CountDownLatch to make the main thread wait until the child thread completed.

    @Test
    public void myTest() {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        new Thread(new Runnable() {
            @Override
            public void run() {
                //write your logic here
                countDownLatch.countDown();
            }
        }).start();
        //wait until the child thread completed.
        countDownLatch.await();
    }