It is possible to synchronize a test case to your Application Under Test (AUT) using fixed-time syncronization (snooze
) or variable-time synchronization (waitFor
, waitForObject
, waitForObjectExists
). Fixed-time synchronization should be avoided, if possible, in favor variable-time synchronization. Reasons include:
- The correct amount of time for an action on one system might not be the correct amount of time for the same action on another system.
- Fixed-time snoozes add up, especially if they happen in loops, increasing the overall test execution time.
- Fixed-time snoozes are artificial: they do not reflect nor adapt to variable application performance which can occur even on the same system.
Here, we present three use cases where an initial example script uses only fixed-time synchronization, and we re-design the script to use variable-time synchronization. These examples demonstrate synchronization by way of GUI test scripts authored in the Squish GUI Tester framework.
What is Synchronization and Why Do I Need It?
Synchronization -- of your application and your test script -- is necessary to prevent your test (and the tool running it) from running too fast for your application's toolkit to keep up. Synchronization gives your AUT the time it needs to process events before moving to the next line of the script.
Inserting snooze()
statements is the simplest method of synchronizing your AUT and script, but it's often insufficient for creating robust tests for the reasons listed above. Let's have a look at some examples.
Use Case 1: Waiting for Objects to Appear
Here's an sample script in Python:
clickButton(waitForObject(names.open_PushButton))
# webView takes 25-30 seconds to appear
snooze(25)
webView = waitForObject(names.webView)
# loading web contents takes up to 10 seconds
snooze(10)
The first snooze adds a delay to avoid a timeout in the following waitForObject()
call, awaiting the webview
becoming visible and available for GUI interaction. Our script assumes webview
readiness in 25 seconds or less. But is that robust, or even accurate?
We could instead allow a (much) longer timeout on waitForObject
. The amount is measured in milliseconds, and this waitForObject now has a timeout of 30 seconds instead of 20, the default.
clickButton(waitForObject(names.open_PushButton))
webView = waitForObject(names.webView, 30000)
# loading web contents takes up to 10 seconds
snooze(10)
This replaces an inflexible, brittle snooze() with a safer padding.
Use Case 2: Waiting for Data to Load or Process
If we are waiting for a complex object that needs to load or process data, a short snooze()
after the waitForObject
might be used, but if there is another condition or property which changes in your AUT once the data is fully loaded, you could waitFor(that) instead. Here's an example:
clickButton(waitForObject(names.open_PushButton))
webView = waitForObject(names.webView, 30000)
# loading web content can take up to 10 seconds
waitFor(lambda: webView.loadProgress == 100, 10000)
(remove the #comment on 10 seconds, not needed here)
Use Case 3: Verifying That an Object Is Not Ready For User Interaction
A snooze()
before a findObject()
might happen if we need to verify that a certain GUI object is disabled or invisible.
snooze(10)
goButton = findObject(names.goButton)
test.verify(goButton.enabled == False)
In this case, waitForObject
cannot be used because it also requires objects to be visible and enabled. The first two statements can be replaced by waitForObjectExists()
instead, provided the timeout is long enough:
goButton = waitForObjectExists(names.goButton)
test.verify(goButton.enabled == False)
Conclusion
Variable-time synchronization approaches are recommended for their robustness and flexibility, especially in cross-platform GUI testing. Here, we saw how Squish offers a number of ways to get around hardcoded delays in your script. Avoiding fixed-time synchronization with snooze()
can help improve the overall runtime of your tests, getting you your results faster.
Recommendations for Further Reading
More on synchronization using the waitFor()
function is provided in this blog.