Bird
Raised Fist0
Selenium Pythontesting~15 mins

Retry mechanism for flaky tests in Selenium Python - Build an Automation Script

Choose your learning style10 modes available
Verify retry mechanism for flaky login test
Preconditions (2)
Step 1: Open the login page URL
Step 2: Enter 'testuser' in the username input field with id 'username'
Step 3: Enter 'Test@1234' in the password input field with id 'password'
Step 4: Click the login button with id 'loginBtn'
Step 5: Wait for the dashboard page to load
Step 6: Verify the URL is 'https://example.com/dashboard'
Step 7: If the verification fails, retry the entire login process up to 2 more times
✅ Expected Result: The test should pass if the dashboard URL is reached within 3 attempts. If all attempts fail, the test should fail.
Automation Requirements - Selenium with Python unittest
Assertions Needed:
Assert current URL equals 'https://example.com/dashboard' after login
Best Practices:
Use explicit waits to wait for page elements or URL changes
Implement retry logic using a loop or decorator
Use clear and maintainable locators (By.ID)
Keep test code readable and modular
Automated Solution
Selenium Python
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class TestLoginWithRetry(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(5)  # Implicit wait for element presence
        self.wait = WebDriverWait(self.driver, 10)  # Explicit wait

    def login(self):
        self.driver.get('https://example.com/login')
        username_input = self.wait.until(EC.presence_of_element_located((By.ID, 'username')))
        password_input = self.driver.find_element(By.ID, 'password')
        login_button = self.driver.find_element(By.ID, 'loginBtn')

        username_input.clear()
        username_input.send_keys('testuser')
        password_input.clear()
        password_input.send_keys('Test@1234')
        login_button.click()

        # Wait for URL to change to dashboard
        self.wait.until(EC.url_to_be('https://example.com/dashboard'))

    def test_login_with_retry(self):
        max_attempts = 3
        for attempt in range(1, max_attempts + 1):
            try:
                self.login()
                current_url = self.driver.current_url
                self.assertEqual(current_url, 'https://example.com/dashboard')
                print(f'Login succeeded on attempt {attempt}')
                break
            except (AssertionError, Exception) as e:
                print(f'Attempt {attempt} failed: {e}')
                if attempt == max_attempts:
                    self.fail(f'Login failed after {max_attempts} attempts')

    def tearDown(self):
        self.driver.quit()

if __name__ == '__main__':
    unittest.main()

This test script uses Python's unittest framework with Selenium WebDriver.

setUp: Initializes the Chrome browser and sets implicit and explicit waits.

login method: Opens the login page, fills username and password fields, clicks login, and waits explicitly for the dashboard URL.

test_login_with_retry: Tries to login up to 3 times. If the dashboard URL is reached, it passes. If not, it retries. After 3 failures, the test fails.

tearDown: Closes the browser after the test.

This approach uses explicit waits for reliability and a retry loop to handle flaky failures like slow page loads or temporary glitches.

Common Mistakes - 4 Pitfalls
{'mistake': 'Using time.sleep() instead of explicit waits', 'why_bad': 'Sleeping blindly wastes time and can cause flaky tests if the page loads slower or faster than expected.', 'correct_approach': "Use Selenium's explicit waits like WebDriverWait with expected conditions to wait only as long as needed."}
Hardcoding XPath locators that are brittle
Not catching exceptions during retries
{'mistake': 'Retrying only the assertion without re-running the login steps', 'why_bad': "If the login process failed, just re-checking the assertion won't fix the problem.", 'correct_approach': 'Retry the entire login process including navigation and input steps.'}
Bonus Challenge

Now add data-driven testing with 3 different sets of login credentials (valid and invalid) to verify retry mechanism works for each case.

Show Hint

Practice

(1/5)
1. What is the main purpose of a retry mechanism in Selenium tests?
easy
A. To permanently ignore failed tests without rerunning
B. To speed up test execution by running tests in parallel
C. To rerun tests that fail due to temporary issues like slow loading
D. To generate detailed logs for every test step

Solution

  1. Step 1: Understand flaky tests

    Flaky tests fail sometimes due to temporary problems like slow page loads or network delays.
  2. Step 2: Purpose of retry mechanism

    Retry mechanism reruns failed tests to check if failure was temporary, reducing false failures.
  3. Final Answer:

    To rerun tests that fail due to temporary issues like slow loading -> Option C
  4. Quick Check:

    Retry mechanism = rerun flaky tests [OK]
Hint: Retry fixes temporary failures by rerunning tests [OK]
Common Mistakes:
  • Thinking retry speeds up tests
  • Assuming retry ignores failures
  • Confusing retry with logging
2. Which of the following is the correct way to implement a simple retry decorator in Python for Selenium tests?
easy
A. def retry(func): try: func() except Exception: func()
B. def retry(func): def wrapper(): for _ in range(3): try: return func() except Exception: pass return wrapper
C. def retry(func): while True: func() return func
D. def retry(func): for _ in range(3): func() return func

Solution

  1. Step 1: Check retry decorator structure

    def retry(func): def wrapper(): for _ in range(3): try: return func() except Exception: pass return wrapper defines a wrapper function that tries to run the test 3 times catching exceptions.
  2. Step 2: Verify retry logic correctness

    def retry(func): def wrapper(): for _ in range(3): try: return func() except Exception: pass return wrapper retries on exception and returns on success, which is correct retry behavior.
  3. Final Answer:

    def retry(func): def wrapper(): for _ in range(3): try: return func() except Exception: pass return wrapper -> Option B
  4. Quick Check:

    Retry decorator = try 3 times with exception catch [OK]
Hint: Retry decorator wraps function with try-except loop [OK]
Common Mistakes:
  • Not catching exceptions inside loop
  • Infinite loops without exit
  • Calling function multiple times without try-except
3. Given this retry decorator and test function, what will be printed?
def retry(func):
    def wrapper():
        for i in range(2):
            try:
                return func()
            except Exception:
                print(f"Retry {i+1} failed")
        print("All retries failed")
    return wrapper

@retry
def test():
    print("Running test")
    raise Exception("Fail")

test()
medium
A. Running test Retry 1 failed Running test Retry 2 failed All retries failed
B. Running test All retries failed
C. Running test Retry 1 failed Retry 2 failed
D. Running test Retry 1 failed Running test Retry 2 failed

Solution

  1. Step 1: Analyze retry loop

    The wrapper tries to run test twice. Each time test() prints "Running test" then raises Exception.
  2. Step 2: Trace output

    On first try, prints "Running test", then exception triggers "Retry 1 failed". Second try repeats same steps, then prints "Retry 2 failed". After loop ends, prints "All retries failed".
  3. Final Answer:

    Running test Retry 1 failed Running test Retry 2 failed All retries failed -> Option A
  4. Quick Check:

    Retry prints on each failure, then final failure message [OK]
Hint: Each retry prints failure message, then final failure after loop [OK]
Common Mistakes:
  • Missing repeated 'Running test' print
  • Ignoring final 'All retries failed' print
  • Assuming retry stops after first failure
4. You wrote this retry decorator but it does not retry on failure. What is the bug?
def retry(func):
    def wrapper():
        for _ in range(3):
            try:
                func()
            except Exception:
                continue
    return wrapper
medium
A. The decorator is missing the @functools.wraps(func) call
B. The except block should raise the exception instead of continue
C. The loop should be a while loop instead of for loop
D. The function does not return the result or stop retrying on success

Solution

  1. Step 1: Check retry logic

    The wrapper calls func() but never returns its result or breaks loop on success.
  2. Step 2: Effect of missing return

    Without return, wrapper always completes loop and returns None, so retry never stops on success.
  3. Final Answer:

    The function does not return the result or stop retrying on success -> Option D
  4. Quick Check:

    Missing return causes always 3 retries even on success [OK]
Hint: Always return on success to stop retries [OK]
Common Mistakes:
  • Not returning function result inside try
  • Misusing continue in except block
  • Ignoring decorator metadata preservation
5. You want to implement a retry mechanism in Selenium tests that retries up to 3 times with a 2-second delay between tries. Which code snippet correctly implements this?
hard
A. import time def retry(func): def wrapper(): for i in range(3): try: return func() except Exception: if i < 2: time.sleep(2) else: raise return wrapper
B. import time def retry(func): def wrapper(): for _ in range(3): try: func() except Exception: time.sleep(2) return wrapper
C. def retry(func): def wrapper(): try: return func() except Exception: time.sleep(2) return func() return wrapper
D. import time def retry(func): def wrapper(): while True: try: return func() except Exception: time.sleep(2) return wrapper

Solution

  1. Step 1: Check retry count and delay

    import time def retry(func): def wrapper(): for i in range(3): try: return func() except Exception: if i < 2: time.sleep(2) else: raise return wrapper retries 3 times with a 2-second sleep between tries except after last attempt.
  2. Step 2: Verify exception handling

    import time def retry(func): def wrapper(): for i in range(3): try: return func() except Exception: if i < 2: time.sleep(2) else: raise return wrapper raises exception after last retry, correctly stopping retries on failure.
  3. Final Answer:

    import time def retry(func): def wrapper(): for i in range(3): try: return func() except Exception: if i < 2: time.sleep(2) else: raise return wrapper -> Option A
  4. Quick Check:

    Retry with delay and raise after last try [OK]
Hint: Use loop with sleep and raise after last retry [OK]
Common Mistakes:
  • Not raising exception after last retry
  • Missing delay between retries
  • Retrying infinitely without limit
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard