Testing Asynchronous Systems
Syed Rehan Ahmed
Manager SQA | Test Automation | Test Architect | OTT | Fintech | Ride Hailing | MS Project Management | ISTQB-CTFL? Certified
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:
SDET Professional | Enhancing Agile Teams with Scalable Testing Frameworks and Robust Automation
2 年Excellent ??
Software Eng @ CME | iOS Developer | Flutter | Django
3 年Osama Aqeel