Q10 of 17 · Framework design

How is dependency injection used in test automation frameworks, and what problem does it solve?

Framework designSeniorframework-designdependency-injectiondispringfixturesadvanced

Short answer

Short answer: DI in test frameworks removes hardcoded construction of dependencies (driver, API clients, DB helpers) inside test classes. Instead, dependencies are created once per scenario/test and injected — enabling easier mocking, parallel isolation, and framework replacement without touching tests.

Detail

The problem without DI:

public class LoginTest {
    // Hardcoded dependency creation — couples test to implementation
    private WebDriver driver = new ChromeDriver();
    private LoginPage loginPage = new LoginPage(driver);

    @Test
    public void validLoginTest() { ... }
}

Changing to Firefox means changing every test class. Tests are impossible to unit-test because you can't swap ChromeDriver for a mock.

With DI — Spring (Java):

@SpringBootTest
@ExtendWith(SpringExtension.class)
public class LoginTest {
    @Autowired
    private WebDriver driver;  // Created by Spring, injected here

    @Autowired
    private LoginPage loginPage;

    @Test
    public void validLoginTest() { ... }
}

@Configuration
public class WebDriverConfig {
    @Bean
    @Scope("prototype")  // new instance per test
    public WebDriver webDriver() {
        return new ChromeDriver(options());
    }
}

Playwright fixtures as DI:

// Playwright's fixture system IS dependency injection
const test = base.extend<{ loginPage: LoginPage; apiClient: ApiClient }>({
  loginPage: async ({ page }, use) => {
    await use(new LoginPage(page));
  },
  apiClient: async ({}, use) => {
    const client = new ApiClient(config.apiUrl);
    await client.authenticate();
    await use(client);
    await client.logout();
  },
});

test('user can view orders after login', async ({ loginPage, apiClient }) => {
  // loginPage and apiClient injected, created fresh per test
});

Benefits:

  • Swap ChromeDriver for a mock in unit tests without touching test code
  • Each parallel test gets its own scoped dependencies — no cross-test state
  • Centralised driver/client construction — one config change applies everywhere

// WHAT INTERVIEWERS LOOK FOR

The problem DI solves (tight coupling, no mockability). At least one concrete implementation (Spring, PicoContainer, or Playwright fixtures). Parallel isolation benefit.