简体   繁体   中英

How to get ExecutorService or CompletionService to finish without asking for values of Futures?

We have some work to be done within a thread which will be run on a server for a web app using Spring Boot .

What we want to happen is: 1) Work is submitted as our custom Runnable object 2) Work completes when it gets its turn (it's a database operation, and we don't need any return value except perhaps returning "Success" if the run() completed without exceptions)

However, in our JUnit tests, it seems all the tasks submitted to an ExecutorService or CompletionService disappear when the main thread is finished, unless we call take() every time we add a new task (since it blocks until a task is finished, this makes tasks run sequentially, which defeats the purpose) or if we maintain a list of futures and call a method to loop through the list and get() the value of each feature.

The latter option we don't think is ideal because as a server application, we will have requests constantly coming in from different users and don't know how to detect when we should be clearing out the list of futures.

Why do the threads silently disappear and what is a way around this?

Don't run the code async: Just test the Runnable directly:

@Test
public void test() {
    Runnable r = <your runnable>;
    r.run();
    // various assertions
}

It's pointless testing that your chosen ExecutorService does its job - you can assume that.

If you want to assert that your application is behaving correctly, use functional tests; ie, spin up a container (eg using @SpringJUnit4ClassRunner ) with a hypersonic datasource, hit the spring boot end point then make you assertions about effect on the database.

If you use spring boot's @Async annotation for your service, you can even provide a configuration that uses a SynchronousTaskExecutor so you don't have to pause in your test before making assertions.

One good approach to testing async code is to block the main test thread and perform assertions in callbacks using something like ConcurrentUnit . Here's an example using a CompletableFuture's whenComplete callback:

Waiter waiter = new Waiter();

CompletableFuture<Connection> future = someService.connect();
future.whenComplete((connection, failure) -> {
  // Called from some other thread
  waiter.assertNotNull(connection);
  waiter.assertNull(failure);
  waiter.resume();
});

// Block the main test thread
waiter.await();

If either of the assertions in the callback thread fail, the test will fail as expected. The main test thread will await a resume call before completing the test.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM