QA
Senior SDETFrameworks & Design PatternsFree question

How do you apply SOLID principles in a test automation framework?

60-second answer

Single responsibility: each class has one reason to change, so page objects model pages, API clients call APIs, and tests verify behaviour. Open-closed: I extend behaviour without editing core code, like adding a new browser through a new factory branch or a new reporter through a listener. Liskov substitution: any WebDriver or any implementation of my ApiClient interface can be swapped without breaking tests. Interface segregation: small interfaces like Clickable or Searchable instead of one huge BasePage. Dependency inversion: tests depend on abstractions injected through fixtures or DI, not on concrete drivers or environments.

Explanation

Smells SOLID fixes in test code:

  • A 3,000-line CommonUtils (violates SRP).
  • if (browser == ...) scattered everywhere (OCP).
  • Tests instantiating new ChromeDriver() directly (DIP).
  • BasePage with 80 methods nobody fully uses (ISP).

Senior-level point: apply principles pragmatically. Test code should stay simple and readable; over-abstraction is also a smell.

Example

Payment tests depend on a PaymentGateway interface. Locally it's a WireMock-backed fake, in staging the real sandbox. Swapping is a config change, not a code change.

Sample code

public interface PaymentGateway {
    PaymentResult charge(String orderId, BigDecimal amount);
}

public class SandboxGateway implements PaymentGateway { /* real sandbox API */ }
public class FakeGateway implements PaymentGateway {    /* in-memory, deterministic */
    public PaymentResult charge(String id, BigDecimal amt) { return PaymentResult.success(id); }
}

public class CheckoutTest extends BaseTest {
    private final PaymentGateway gateway = Gateways.fromConfig();  // injected by config
}