Testing Asynchronous Systems

Testing Asynchronous Systems

Learning how async systems work and how to get them tested, I came across a Java Library (framework) that makes it easier to write tests that are readable, Awaitility.

Awaitility helps to write tests not only more readable format but also makes it easy to test async code. Let's take an example of a system where you are using Rest APIs need to get the acknowledgment from the other system and you have to wait for a certain time to get it tested, in scenarios like these you need to wait or add Thread.sleep() in your test to get the desired acknowledgment before moving forward otherwise you get the assertion error (java.lang.AssertionError ),

Response response = given().
                    contentType(ContentType.JSON).
                    header("X-Auth-Token",auth_token).
                    when().
                    get(“https://sample URL”);
Thread.sleep(5000);
Assert.assertEquals(response.path(“Status”), “Success”);
        

Now consider your application has multiple APIs that have the same problem, you'll keep increasing your build time by adding multiple waits. Awaitility helps you cater to these problems by giving,

asyncService.initialize();
await()
    .atLeast(Duration.ONE_HUNDRED_MILLISECONDS)
    .atMost(Duration.FIVE_SECONDS)
  .with()
    .pollInterval(Duration.ONE_HUNDRED_MILLISECONDS)
    .until(asyncService::isInitialized);        

So it will hit for at least 100 milliseconds, at max for 2 seconds, it fails to try again after 100 milliseconds until returns true, we use the conditions in a different manner like Wait forever until the call,

await().until( userRepositorySize(), equalTo(1) );        

OR

await().until( fieldIn(object).ofType(int.class), equalTo(2) );        

You can refer to the usage of the conditions from their git documentation usage. We can further enhance its performance by adding poll interval, 100 milliseconds with a delay of 20 milliseconds until the condition is true,

with().pollDelay(100, MILLISECONDS).and().pollInterval(200, MILLISECONDS).await().until(<condition>);        

By default, Awaitility will wait for 10 seconds and if the size of the user repository is not equal to 1 during this time it'll throw a ConditionTimeoutException failing the test. If you want to set different default timeouts you can define it as,

  Awaitility.setDefaultTimeout(..
  Awaitility.setDefaultPollInterval(..)
  Awaitility.setDefaultPollDelay(..))        

Another common problem with asynchronous systems is that it's hard to write readable tests for them that are focused on business logic and are not polluted with synchronizations, timeouts, and concurrency control. With Awaitility, we can express our expectations from the system in an easy-to-read DSL.

asyncService.initialize();
await()
  .until(asyncService::isInitialized);        

Here, we use await — one of the static methods of the Awaitility class. It returns an instance of a ConditionFactory class. We can also use other methods like given for the sake of increasing readability.

We can also use proxy to provide real method calls for conditions without the implementation of a Callable or lambda expression. Let's use the AwaitilityClassProxy.to static method to check that AsyncService is initialized:

asyncService.initialize();
await()
  .untilCall(to(asyncService).isInitialized(), equalTo(true));        

The Implementation

We need to add Awaitility dependencies to our pom.xml.

The awaitility library will be sufficient for most use cases. In case we want to use proxy-based conditions, we also need to provide the awaitility-proxy library

<dependency>
    <groupId>org.awaitility</groupId>
    <artifactId>awaitility</artifactId>
    <version>4.1.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.awaitility</groupId>
    <artifactId>awaitility-proxy</artifactId>
    <version>3.1.6</version>
    <scope>test</scope>
</dependency>
        

In learning TDD with async this Awaitility must be a good help for asynchronous API tests and their implementation. Awaitility library is flexible and easy to use in real projects for testing asynchronous systems. It Allows polling until a certain condition becomes true thereby dealing with processing time.

Learn More:

  • https://github.com/awaitility/awaitility#documentation
  • https://www.baeldung.com/awaitlity-testing
  • https://tektutorialcom.wordpress.com/2019/07/11/awaitility-with-spring-boot/

To view or add a comment, sign in

More articles by Syed Rehan Ahmed

  • Automating Web Performance - Google Page Speed Insights API

    Website Performance One of the key factor for web performance is the how long it take to load page, reder resources…

    1 Comment
  • Android Applications Testing - Helpful Tools

    For the Mobile Apps Testers, there are areas where we need to go beyond the functional testing part, as its just one…

    2 Comments
  • Test Driven Development & Role of QA

    Software development is an evolving field, theres always new trends and technology enhancements with every new day, in…

    1 Comment
  • Android TDD and Roboelectric

    I have been learning about Android development and test-driven development lately, came across the Roboelectric…

    1 Comment

Others also viewed

Explore content categories