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/

Fakhar Ud Din Khokhar

SDET Professional | Enhancing Agile Teams with Scalable Testing Frameworks and Robust Automation

2 年

Excellent ??

回复
Syed Rafay

Software Eng @ CME | iOS Developer | Flutter | Django

3 年

要查看或添加评论,请登录

Syed Rehan Ahmed的更多文章

  • Automating Web Performance - Google Page Speed Insights API

    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 条评论
  • Android Applications Testing - Helpful Tools

    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 条评论
  • Test Driven Development & Role of QA

    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 条评论
  • Android TDD and Roboelectric

    Android TDD and Roboelectric

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

    1 条评论

社区洞察

其他会员也浏览了