Developing Microservices and Test Workflows: A Selenium Testing Case Study

In our journey to improve MorphoSource’s reliability and user experience, we’ve developed a comprehensive testing framework using Selenium WebDriver. Today, we’ll explore how we’ve structured our automated testing suite to handle both 2D and 3D content, highlighting the evolution from a simple script to a robust, production-ready solution.

The Evolution of Our Testing Framework

Our testing framework started with a basic 2D image testing script but has grown into a sophisticated system capable of handling complex 3D models. This evolution reflects our broader journey in microservices development, where we’ve learned to build resilient, maintainable systems.

From Simple Scripts to Robust Solutions

Let’s compare our initial 2D testing approach with our enhanced 3D testing solution:

Initial 2D Testing (Simple Approach)

def test_fullscreen_screenshot():
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    driver = webdriver.Chrome(options=options)
    try:
        driver.get("https://www.morphosource.org/concern/media/000695203")
        # Basic screenshot logic...
    finally:
        driver.quit()

Enhanced 3D Testing (Production-Ready)

def test_fullscreen_screenshot(url):
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    options.add_argument('--disable-web-security')
    options.add_argument('--disable-features=IsolateOrigins,site-per-process')
    driver = webdriver.Chrome(options=options)
    try:
        # Enhanced navigation and screenshot logic...
        take_screenshot_with_retry(driver, screenshot_name)
    finally:
        driver.quit()

Key Improvements in Our Architecture

1. Robust Error Handling

We’ve implemented comprehensive error handling with retry mechanisms:

def take_screenshot_with_retry(driver, screenshot_name, max_retries=3):
    for attempt in range(max_retries):
        try:
            driver.save_screenshot(screenshot_name)
            return True
        except TimeoutException as e:
            if attempt < max_retries - 1:
                time.sleep(wait_between_retries)
            else:
                raise

2. Configuration Management

We’ve moved from hardcoded values to flexible configuration:

DEFAULT_URL = "https://www.morphosource.org/concern/media/000699150"

def parse_arguments():
    parser = argparse.ArgumentParser(description='Run Selenium fullscreen test')
    parser.add_argument('--url', type=str, help='URL to test (optional)', 
                       default=DEFAULT_URL)
    return parser.parse_args()

3. Enhanced Browser Configuration

Our production setup includes carefully tuned browser settings:

options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-gpu')
options.add_argument('--start-maximized')
options.add_argument('--window-size=1920,1080')

Microservices Best Practices Learned

1. Isolation and Independence

Each test module operates independently, following microservices principles:

2. Resilience and Recovery

We’ve implemented multiple layers of resilience:

3. Monitoring and Observability

Our framework includes comprehensive logging:

def test_fullscreen_screenshot(url):
    start_time = datetime.now()
    try:
        print(f"Testing URL: {url}")
        # Test execution...
    finally:
        end_time = datetime.now()
        duration = end_time - start_time
        print(f"Total execution time: {duration}")

Lessons Learned and Best Practices

  1. Progressive Enhancement: Start simple and add complexity as needed. Our 2D testing script was a foundation for more complex 3D testing.

  2. Defensive Programming: Always prepare for failures:
    • Implement retry mechanisms
    • Handle timeouts gracefully
    • Clean up resources in finally blocks
  3. Configuration Management: Make your services configurable:
    • Command-line arguments
    • Environment variables
    • Default values for flexibility
  4. Performance Monitoring: Track execution times and system behavior:
    • Log start and end times
    • Monitor resource usage
    • Track success rates

Looking Forward

As we continue to develop our testing infrastructure, we’re focusing on:

  1. Scaling: Implementing parallel test execution for faster results
  2. Reporting: Enhanced logging and metrics collection
  3. Integration: Tighter coupling with our CI/CD pipeline

Conclusion

The evolution of our Selenium testing framework mirrors the broader journey of microservices development. By applying principles of resilience, observability, and maintainability, we’ve created a robust testing solution that supports our growing platform.

As we continue to enhance MorphoSource, these lessons in microservices architecture and test automation will guide our future development, ensuring we maintain high quality and reliability in our service delivery.


← Previous Post $~~~~~~~~~~~$ Next Post →