Q36 of 38 · Test design
How do you design for reusability in a test suite that has grown to hundreds of test cases?
Short answer
Short answer: Apply layered architecture: a data layer (factories), an action layer (reusable steps for common user actions), and a test layer (tests that compose those actions). Avoid test-level abstractions that couple tests together — each test should be independently runnable.
Detail
The anti-pattern: copying setup code across tests. When the login sequence is duplicated in 50 tests and the login flow changes, 50 tests break simultaneously.
The architecture:
Data layer: factory functions that create and clean up test data with minimal coupling to test logic.
Action/component layer: reusable steps for common flows — loginAs(user), addItemToCart(item), navigateTo(page). These wrap the framework API and are the single place where selectors and flow logic live.
Test layer: tests that compose action-layer calls to describe a scenario. The test reads like a specification; implementation details are in the layers below.
The constraint: reusability must not create coupling. A shared helper that modifies shared state means tests can only run in a specific order — which breaks parallelisation and makes failures non-deterministic. Each test must be able to create its own state, run, and clean up independently.
For very large suites, a test tagging taxonomy (smoke, regression, slow, feature-X) lets you run targeted subsets efficiently.