Designing Test Frameworks That Survive Their Second Year
Most automation frameworks rot within a year. The fix isn't a better tool — it's treating the framework as production software with real architecture.
Most test automation frameworks start clean and end as a graveyard of flaky tests nobody trusts. The tool is rarely the problem. The problem is that the framework was written as a pile of scripts instead of as software.
The symptom vs. the cause
Teams usually blame the symptom — flakiness, slow runs, brittle locators — and reach for a new tool. A year later they’re back in the same place, because the underlying cause was structural, not technological.
The frameworks that survive share one trait: the test author never touches infrastructure code. Waiting, driver setup, configuration, and reporting live behind stable interfaces.
A layered structure
Think in three layers, each depending only on the one below it:
- Tests — express intent, nothing else.
- Domain / page objects — model the application.
- Core — driver lifecycle, waits, config, reporting.
// A test says WHAT, never HOW.
@Test
void userCanLogIn() {
loginPage.open()
.signInAs(standardUser);
assertThat(dashboard.isVisible()).isTrue();
}
Notice there’s no WebDriver, no sleep, no locator in sight. That’s the point.
Waiting is a core concern, not a test concern
The single biggest source of flakiness is waiting logic copy-pasted into tests. Centralise it once:
public <T> T until(Function<WebDriver, T> condition) {
return new WebDriverWait(driver, TIMEOUT).until(condition);
}
Now a locator change is one edit, and a timeout tuning is one edit — not fifty.
The test
Here’s the honest measure of a framework’s design: can a new engineer add a meaningful test on their first day without reading the core? If yes, it will survive its second year. If no, it won’t — regardless of the tool on the label.