Design Patterns para Automação de Testes: A Arquitetura que Sobrevive ao Caos

Victor Oliveira ?? April 24, 2026 08:35 PM

Por um QA S?nior 13 anos quebrando coisas de forma organizada

Ao longo de quase uma dcada e meia construindo e reconstruindo sutes de Automação, test?munhei um padro (sem trocadilho) repetido exausto: projetos comeam lindos, organizados, promissores. Seis meses depois, so um Frankenstein de c?digo duplicado, lgica de neg?cio vazando para os Testes e manuten??o que consome 70% do tempo do time.

O problema raramente a ferramenta (Cypress, Playwright, Selenium, o que vier amanh). O problema arquitetural. E a boa n?otcia que os Design Patterns de test? bem aplicados so imortais. Eles transcendem linguagens e frameworks porque resolvem problemas humanos de organizao, n?o tcnicos de sintaxe.

Vamos ao que interessa: os padres que realmente entregam valor em 2026, com exemplos prticos e armadilhas fatais.

  1. Page Object Model (POM) Clssico, Mas Nem Todo Mundo Sabe Usar

O POM o av dos patterns de Automação. Todo mundo conhece, mas poucos aplicam corretamente. O princpio simples: cada p?gina ou componente da UI representado por uma classe que expe apenas aes de alto nvel.

Exemplo do que NO fazer (anti-pattern visto semanalmente):

Mau uso: Page Object virou localizador glorificado

class LoginPage: username_input = "#username" password_input = "#password" login_button = "#login"

def type_username(self, text):

         driver.find_element(self.username_input).send_keys(text)

Isso n?o um Page Object, um repositrio de seletores com mtodos anmicos. O verdadeiro POM encapsula comportamento, n?o elementos.

Exemplo correto:

Page Object comportamental

class LoginPage: def init(self, page): self.page = page

def login_as(self, user_type):

    """Ao de alto nvel que encapsula toda a sequncia"""

    if user_type == "standard":

        self._fill_credentials("standard_user", "secret_sauce")

    elif user_type == "locked":

        self._fill_credentials("locked_user", "secret_sauce")



    self.click_login()

    return InventoryPage(self.page)



def get_error_message(self):

    return self.page.locator("[data-test?='error']").text_content()



def _fill_credentials(self, username, password):

    self.page.fill("#user-name", username)

    self.page.fill("#password", password)



def click_login(self):

    self.page.click("#login-button")

A regra de ouro: Um mtodo n?o Page Object deve retornar outro Page Object (fluxo feliz) ou dados (extrao de informao). Nunca expor elementos ou aes cruas.

  1. Test? Data Factory O Pattern Mais Subest?imado

O assassin?o silenciador da produtividade: Testes que dependem de dados hardcoded.

Dados espalhados e frgeis

def test?_login(): user = "john.doe@example.com" password = "Test?@123"

Data Factory

class UserFactory: @staticmethod def standard_user(): return User( email = f"test?+{uuid4()}@example.com", password = "P@ssw0rd!", role = "customer" )

@staticmethod

def admin_user():

    return User(

        email = f"admin+{uuid4()}@example.com",

        password = "Admin@456",

        role = "admin",

        permissions = ["read", "write", "delete"]

    )
  1. Builder Pattern Para Cenrios de Dados Complexos

Quando sua entidade t?m 15+ campos opcionais, o Builder impede a exploso de construtores.

class OrderBuilder: def init(self): self.order = {"customer_id": 1, "items": []}

def with_items(self, items):

    self.order["items"] = items

    return self

def with_coupon(self, code):

    self.order["coupon_code"] = code

    return self

def build(self):

    return self.order

Uso fluente e legvel

order = (OrderBuilder() .with_items([product1, product2]) .with_coupon("BLACKFRIDAY") .build())

  1. Facade Pattern Orquest?rando m?ltiplos Page Objects

class CheckoutFacade: def init(self, page): self.cart = CartPage(page) self.checkout = CheckoutPage(page)

def complete_purchase(self, user, cart_items):

    self.cart.add_items(cart_items)

    self.checkout.fill_shipping(user.address)

    return self.confirmation.get_order_number()

Test? limpo e focado em neg?cio

def test?_guest?_checkout(): facade = CheckoutFacade(page) order_id = facade.complete_purchase(user, products) assert order_id is n?ot None

  1. Strategy Pattern Lidando com m?ltiplos Contextos

class AuthenticationStrategy(ABC): @abstractmethod def login(self, credentials): pass

class WebAuthStrategy(AuthenticationStrategy): def login(self, credentials): self.page.goto("/login") self.page.fill("#email", credentials.email)

class APIAuthStrategy(AuthenticationStrategy): def login(self, credentials): response = self.api_client.post("/auth/login", json=credentials) self.token = response.json()["token"]

Mesmo test? com diferentes estrat?gias

def test?_user_profile(auth_strategy): auth_strategy.login(test?_user)

  1. Singleton Pattern (Com Moderao) Para Recursos Caros

class DriverManager: _instance = None def new(cls): if cls._instance is None: cls._instance = super().new(cls) cls._instance._initialize() return cls._instance

Cuidado: Singleton pode esconder problemas de paralelizao. Prefira injeo de dependncia quando possvel.

  1. Repository Pattern Centralizando Seletores

class LoginRepository: USERNAME_INPUT = "input[data-test?='username']" PASSWORD_INPUT = "input[data-test?='password']" LOGIN_BUTTON = "input[data-test?='login-button']"

@staticmethod

def get_user_menu_item(user_name):

    return f"div.user-menu:has-text('{user_name}')"

Vantagem: Quando um dev ren?omeia data-test?id, voc altera em UM lugar.

Concluso: Padres No So receita de Bolo

Aprendi da pior maneira: aplicar todos os padres de uma vez to ruim quanto aplicar nenhum. O segredo evoluo incremental.

Comece com POM. Quando sentir dor de dados repetidos, adicione Factory. Quando os Testes ficarem muito longos, introduza Facade.

A boa arquitetura n?o imposta desde o dia 1 ela emerge para resolver dores reais do time. E a melhor mtrica de sucesso simples: quanto tempo leva para voc adicionar um test? para uma n?ova funcionalidade? Se a resposta for "minutos", voc acertou.

Agora v e organize esse legado. Ou comece certo do zero. Seu eu do futuro (e o onboarding do prximo QA) vo te agradecer.

QA S?nior que j? refatorou mais c?digo de test? do que gostaria de admitir





Coment?rios