Language: Java
Testing/Async
Testing asynchronous operations in Java can be challenging due to timing and concurrency issues. Awaitility was created to simplify this by providing a clean, readable API to wait for conditions without using Thread.sleep() or complex polling logic. It is widely used in unit tests, integration tests, and reactive systems testing.
Awaitility is a Java DSL (Domain Specific Language) for testing asynchronous code. It allows developers to wait for a certain condition to be met within a specified time period, making testing of async operations, background tasks, or event-driven systems more reliable and readable.
Add dependency in pom.xml:
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>Add dependency in build.gradle:
testImplementation 'org.awaitility:awaitility:4.2.0'Awaitility allows you to define expectations using conditions, durations, and polling intervals. It integrates with JUnit, TestNG, and other test frameworks, making async testing straightforward.
import static org.awaitility.Awaitility.await;
import java.util.concurrent.TimeUnit;
boolean[] flag = {false};
new Thread(() -> {
Thread.sleep(1000);
flag[0] = true;
}).start();
await().atMost(5, TimeUnit.SECONDS).until(() -> flag[0]);Waits up to 5 seconds until the `flag` variable becomes true, allowing asynchronous threads to complete.
import static org.awaitility.Awaitility.await;
import java.util.concurrent.atomic.AtomicInteger;
AtomicInteger counter = new AtomicInteger(0);
new Thread(() -> counter.incrementAndGet()).start();
await().untilAtomic(counter, val -> val > 0);Waits for an AtomicInteger to become greater than 0.
await().atMost(10, TimeUnit.SECONDS).pollInterval(500, TimeUnit.MILLISECONDS)
.until(() -> myService.isReady());Polls every 500 milliseconds for a condition to become true, with a maximum timeout of 10 seconds.
await().atMost(5, TimeUnit.SECONDS).ignoreExceptions()
.until(() -> externalService.getData() != null);Ignores transient exceptions while waiting for a condition, useful for unstable or delayed async services.
import static org.hamcrest.Matchers.*;
await().atMost(3, TimeUnit.SECONDS).until(() -> list.size(), equalTo(5));Uses Hamcrest matchers to define more expressive conditions.
Avoid using Thread.sleep() in tests; prefer Awaitility for readability and reliability.
Define reasonable timeouts to prevent tests from hanging indefinitely.
Use atomic variables or thread-safe constructs for shared state in async tests.
Integrate with JUnit or TestNG to run async tests seamlessly.
Use polling intervals to balance responsiveness and CPU usage during waits.