Synchronizing API checks with rest_easy

I was catching up on some testing podcasts and just recently came across Joe Colantonio’s episode on The Top 6 Automation Best Practices. The number one tip was synchronization.

Synchronization is the term Joe uses to mean “timing everything up right.” I’m sure we’ve all come across a problem with this in some form or another. Slow AJAX requests, advertising iframes, modal pop ups, etc.

In my experience, it’s often a pain for test engineers.

easy way out

The easiest (laziest) way to deal with timing issues is hard coding pauses into your tests. Perform an action, sleep for 5 seconds, then validate or perform another action.

But this introduces inefficiency and flakiness into the tests.

70% of the time, your tests could continue after 3 seconds. And 10% of the time, 5 seconds isn’t enough. Your tests are going to be slow and fail occasionally.

There’s simply nothing worse than an occasionally failing test.

API sandbox headaches

I was testing a web application and validating frontend actions through API calls, but a lot of these calls were to third-party sandbox APIs. They were terribly slow, sometimes needing up to a minute to return the expected response.

My tests would mostly fail, but manually following up on the failures would reveal passing API responses. It was a frustrating synch issue.

At first, I hard coded in some sleeps. But that sucked. The wait was always way too much or not quite enough. My run times got longer and 1 in every 10 runs would fail. The whole situation was flakey.

And I hate flake.

rest_easy

After a week of synchronization turmoil, I rolled my own solution to the problem. Then I turned that solution into a gem called rest_easy.

My waits dynamically waited around validation blocks and the tests passed if the blocks resolved positively before the timeouts were reached. Otherwise, false was returned and tests failed (but with reason!).

The scripts didn’t change much. Here’s what one may have looked like before rest_easy:

And what it might look like with rest_easy:

under the hood

This is a really simple solution. RestEasy.get_until makes a GET request using the rest-client gem and yields its response to your validation block.

The entirety of the get_until method is written as a block and passed to a timer method. The timer method (RestClient#iterate) will loop over the get_until block until the timeout it reached or the loop is broken by a return from that block.

And this is almost exactly how a Watir::WebDriver wait works too.

conclusion

There’s not much to this post, but I wanted to write about my solution to a synchronization headache after listening to Joe’s podcast.

I haven’t expanded rest_easy much beyond my particular use case, so it only supports GET requests at the moment. But I’m open to enhancing the functionality and pull requests are always welcome.