Design patterns in test automation are proven, reusable solutions that keep test code structured, readable, and extensible. Key patterns include Page Object, which encapsulates web page elements into classes; Builder, which separates object creation from representation; and Facade, which provides a single entry point to grouped functionality. Supporting principles include DRY (do not repeat yourself), KISS (keep it simple), and YAGNI (you aren’t gonna need it).
Key Takeaways
- Design patterns give test automation teams a shared vocabulary, so a problem can be solved by naming a pattern (Builder, Singleton, Facade) rather than re-explaining the solution from scratch.
- Spaghetti test code is the direct result of skipping encapsulation: without patterns like Page Object, selectors and methods scatter across tests and duplication multiplies.
- The YAGNI principle applies to test automation frameworks: implement only what is needed now, and leave extensibility as a structural option, not a pile of unused helpers.
- AI tools will generate overcomplicated test automation code without explicit constraints in the prompt, and a human engineer must still verify and redesign the output.
- The Gang of Four design patterns, published in 1994, remain directly applicable to test automation, especially the creational patterns. The object pool pattern, which is not part of the Gang of Four catalogue, helps manage parallel web driver instances.
Why design patterns belong in test automation code
Test automation code is real code, and it deserves the same care as the production system it checks. Kostiantyn Teltov has spent nearly two decades in software testing with a technical background across C#, Java, JavaScript, TypeScript, and Python. His position is direct: take care of your test automation code, because it grows and outlives the quick prototype you started with.
Design patterns serve four jobs here. They give you a proven solution instead of a reinvented wheel. They enable object-oriented principles, which keeps the code from turning into spaghetti. They create a shared vocabulary in the team. And they support extensibility, so the small framework you build today can scale tomorrow.
That last point is the practical payoff. A test suite that starts as a prototype often becomes the backbone of a larger solution. Patterns are what let it grow without collapsing under its own weight.
What the Page Object pattern solves
The Page Object is the most common pattern in UI test automation, and it exists to stop duplication. Without it, you write all your selectors and methods directly inside your tests, and you repeat them every time you touch the same screen.
A Page Object encapsulates a screen or a web page in a class. If the page is large, you split it into subclasses for the smaller parts. The selectors and the web driver calls live in one place, and the tests call into them.
This works regardless of programming language or test framework. Page Objects are a shared baseline that almost every UI automation engineer reaches for first, which is exactly why they are the natural entry point into pattern thinking.
Builder, Facade, and Pool: three patterns worth knowing
Beyond Page Objects, a handful of patterns earn their place in automation work. Kostiantyn singles out the Builder and the Facade, and points to a non-Gang-of-Four pattern, the object pool, for a specific performance problem.
The Builder separates object creation from object representation. The analogy is a burger: from one constructor you build a cheeseburger or a hamburger by assembling the parts you want. In tests this reads cleanly. Without adopting a full BDD framework like Cucumber or SpecFlow, a Builder makes test setup almost as readable, because the construction steps spell out what the test needs.
The Facade works like a reception desk. You arrive at one class, and from there you reach whatever you need. For an API, a Facade lets you navigate to users, customers, or orders without repeating the same initialization inside every test. You set up the similar classes once, the REST request builders for example, and the tests go through the single entry point.
The object pool addresses memory churn. Imagine creating web drivers in parallel, then closing them, again and again, with memory spiking each time. Instead of creating and destroying on every run, you build a pool, take a driver from it, return the driver to it, and clean up the pool at the end. The idea is simple once someone shows it to you.
Here is a quick orientation on what each pattern is for:
| Pattern | Problem it solves |
|---|---|
| Page Object | Duplicated selectors and web driver calls inside tests |
| Builder | Verbose object setup, hard-to-read test data construction |
| Facade | Repeated initialization and navigation across many classes |
| Object pool | Memory churn from creating and destroying objects repeatedly |
The Gang of Four patterns still hold up
Patterns published in 1994 remain valid decades later. The Gang of Four creational patterns are a good place to start: singleton, factory method, abstract factory, builder, and prototype.
Not all of them carry the same weight today. Prototype, for instance, matters less in modern languages, because you can already copy objects under the hood without it. The others still find regular use, depending on what you are building.
Design principles sit alongside the patterns. The dependency inversion principle, implemented through dependency injection, is one Kostiantyn calls out as important for automation frameworks. The point is not to apply everything, but to know the catalogue well enough to pick what the situation needs.
DRY and KISS keep test code honest
Do not repeat yourself is the principle that ties most of these patterns together. A Page Object is DRY in action: you stop repeating element lookups and web driver methods by encapsulating them. The same logic extends to assertions you reuse or database calls you make often. Anything that starts to look like spaghetti is usually a repetition you can move into a helper.
Keep it simple guards the other flank. You are not designing the production project. You are designing tests for it, and you do not write tests for your tests. Reach for a pattern only when the problem calls for one, not because you just learned it and want to use it.
“Sometimes when, especially you learn something new, like a new design pattern, you are trying to implement it. But you always need to ask yourself, okay, if it’s suitable here, because sometimes we want to overcomplicate or overdesign.” (Kostiantyn Teltov) You aren’t gonna need it rounds out the set. Build what you need now. Design the framework so it can extend, but do not write helpers for use cases that do not exist yet. Premature scaffolding is its own form of clutter.
How AI handles patterns, and where it overcomplicates
AI can produce pattern-based code, but only if you give it the context, and you still have to verify the result. AI works from prompts, so a pattern appears in the output only when you ask for it. Leave the context out, and it won’t apply one.
The verification matters more than the generation. Kostiantyn prepared a workshop that generated a Playwright framework from scratch with ChatGPT, and during preparation it worked well. A month later, running the same session live on a paid plan, the tool started to overcomplicate, stacking conditional after conditional. He had to redesign the output by hand and tell participants outright that the generated version was not correct.
The lesson is control, not avoidance. AI keeps getting more capable, but the engineer still decides whether the generated code is appropriate or bloated. Knowing the patterns yourself is what lets you make that call.
From copy-paste to fluent: how to actually learn patterns
Most automation engineers start by copying. You join a team, your senior colleagues hand you frameworks and templates, and you copy-paste your way through the early work. That is a normal beginning, not an end state.
The path forward runs through three areas: object-oriented programming where it is required, data structures, and design patterns. Many automation engineers grew out of manual testing rather than development, so these foundations are not always there yet, and they are worth building deliberately.
For sources, Kostiantyn points to the original Gang of Four book on design patterns, the Refactoring Guru website with its illustrated explanations across multiple languages, and free material on YouTube, plus platforms like LinkedIn Learning and Udemy. Reading still pays off, even when long-form reading has fallen out of fashion.
The method that worked for him was social. His team met once a week in the office, prepared short presentations, and then solved practical tasks together using a given pattern. Finding colleagues who push you turns out to be as useful as any book.
Quality knowledge spreads when teams break their bubbles
Patterns stick faster when an organization shares them across teams. At his workplace, Kostiantyn helped start a QA Guild, the first guild in the organization, set up after he made the case to HR.
The guild had a clear purpose: spread knowledge and break bubbles. Each team can work differently and lean on its own approaches, and those silos keep good practices from traveling. A guild is a channel for moving them.
This connects back to one of the four reasons for patterns in the first place. A shared vocabulary only works if it is actually shared. When a teammate hits a problem, being able to say “resolve this with a Builder” or “use a Singleton here” only helps if both sides speak the same language, and a guild is how that language reaches the whole organization.
Frequently Asked Questions
Does test automation code need the same design discipline as production code?
Yes. Test code grows and outlives the quick prototype it started as, and a suite that begins as an experiment often becomes the backbone of a larger solution. Design patterns give four things here: a proven solution instead of a reinvented wheel, working object-oriented structure, a shared vocabulary in the team, and room to extend the framework later.
What turns a UI test suite into spaghetti code?
Missing encapsulation. When selectors and web driver calls sit directly inside the tests, they get repeated every time someone touches the same screen, and duplication multiplies. The Page Object pattern moves a screen or page into its own class, with subclasses for the smaller parts of large pages. The tests then call into that class instead of holding the details themselves.
Can test setup be made readable without adopting a BDD framework?
Yes. A Builder separates object creation from representation, so the construction steps in the test spell out what the test actually needs. Think of assembling a burger: from one constructor you produce a cheeseburger or a hamburger by picking the parts. That gets close to the readability of Cucumber or SpecFlow without pulling in a full BDD framework.
How do you deal with memory spikes when web drivers are created and closed in parallel?
Use an object pool. Instead of creating and destroying a driver on every run, you build a pool once, take a driver from it, return the driver after use, and clean up the pool at the end. The object pool is not part of the Gang of Four catalogue, but it answers this specific performance problem directly.
Are the Gang of Four design patterns still useful decades after publication?
Largely yes. The catalogue published in 1994 still applies to test automation, and the creational patterns are a sensible starting point: singleton, factory method, abstract factory, builder, and prototype. Prototype carries less weight in modern languages, since copying objects already happens under the hood. The dependency inversion principle, implemented through dependency injection, matters for automation frameworks.
When should you not apply a design pattern?
When the problem does not call for one. A common trap is learning a new pattern and then looking for a place to use it, which leads to overdesign. You are designing tests for a product, not the product itself, and you do not write tests for your tests. YAGNI applies too: build what is needed now and leave extensibility as a structural option, not as unused helpers.
Can AI generate pattern-based test automation code reliably?
Only with explicit context in the prompt, and the output still needs human review. Kostiantyn Teltov prepared a workshop that generated a Playwright framework from scratch with ChatGPT, and it worked well during preparation. A month later, live on a paid plan, the tool started stacking conditional after conditional. He redesigned the result by hand and told participants the generated version was not correct.
How can an automation engineer move beyond copy-pasting existing frameworks?
Build three foundations deliberately: object-oriented programming where the work requires it, data structures, and design patterns. Many automation engineers come from manual testing rather than development, so these are often missing. Useful sources include the original Gang of Four book, the illustrated explanations on Refactoring Guru, free YouTube material, LinkedIn Learning, and Udemy. Weekly team sessions with short presentations and shared practical tasks worked well too.


