Tradução do artigo sobre PageObjects

 

O texto abaixo é a uma tradução autorizada do artigo escrito pelo Martin Fowler. Para acessar a versão original em inglês, clique aqui . Caso você tenha sugestões para tornar a tradução melhor, compartilhe através da seção de comentários no final da página.

The text bellow is an authorized translation of the article written by Martin Fowler. To access the original english version, click here . If you have any suggestion to make the translation better, share it via comments section at the end of the page. 

 

Quando você escreve testes para uma página web, você precisa criar referências a elementos na página para clicar nos links e checar o que é exibido. Entretanto, se você escrever testes que manipulem os elementos HTML diretamente seus testes vão estar frágeis a mudanças na UI. Um page object abstrai uma página HTML (ou parte) em uma API específica da aplicação, permitindo você manipular os elementos de página sem se aprofundar no HTML.

 

pageObject

 

A regra básica para um page object é que ele deve permitir um software cliente fazer qualquer coisa e ver qualquer coisa que um humano pode. Ele deve também prover uma interface que seja fácil para programar e esconda as camadas internas da janela. Com isso, para acessar uma caixa de texto você deve ter métodos de acesso que recebam ou retornem uma string, check boxes que permitam usar booleans e botões que devem ser representados por métodos que correspondam a sua ação . O page object deve encapsular os mecânismos necessários para encontrar e manipular os dados no controle da interface gráfica. Uma boa regra é imaginar mudando o elemento de fato – no caso a interface do page object não deve mudar.

Indiferente do termo “page” object, esses objetos não devem geralmente ser construidos para cada página, mas ao invés disso, para elementos relevantes na página. Uma página que exibe vários álbuns, por exemplo, deve ter um page object de uma lista de álbuns, contendo vários page objects de álbuns. Eles deve possivelmente também ter um page object de cabeçalho e um page object de rodapé. Com isso, parte da hierarquia de uma UI complexa existe somente para estruturar a UI – tal composição de estruturas não devem serem reveladas pelos page objects. A idéia é modelar a estrutura da página de modo que faça sentido para o usuário da aplicação.

Da mesma forma, se você navegar para outra página, o page object inicial deve retornar outro page object para a nova página. No geral, operações de page objects devem retornar tipos fundamentais (strings, datas) ou outros page objects.

Existem diferenças de opinião se page objects devem incluir assertions em si, ou simplesmente prover dados para que os scripts de teste façam os assertions. Adeptos por incluir os assertions nos page objects dizem que isso ajuda a evitar duplicação de assertions nos scripts de testes, facilitando a produção de melhores mensagens de erro e suportando mais uma API no estilo TellDonAsk*. Adeptos de page objects sem assertions dizem que a inclusão de assertions misturam as responsabilidades de prover acesso aos dados da página com a lógica de assertions, e levam a um page object inchado.

Eu sou a favor de não criarmos assertions nos page objects. Eu acho que você pode evitar a duplicação criando bibliotecas de assertions para os assertions comuns – o qual pode também facilitar a provisão de diagnósticos.

Page objects são geralmente usados para testes, mas não devem fazer assertions eles mesmos. Sua responsabilidade é providenciar acesso ao estado das partes internas da página. É responsabilidade dos clientes levar a lógica dos assertions.

Eu descrevi esse padrão usando como base o HTML, mas o mesmo padrão pode ser aplicado em qualquer tecnologia de UI. Eu tenho visto esse padrão sendo usado efetivamente para ocultar detalhes de UI em Java Swing e não tenho dúvidas que isso é amplamente usado em quase todas frameworks de UI existentes.

Problemas de concorrência são outro tópico que um page object pode encapsular. Esses casos podem ter que ocultar a assíncronia em operações assíncronas que não podem serem exibidas ao usuário como assíncronas. Page objects podem encapsular problemas de threads em frameworks UI onde você tem que se preocupar em um comportamento entre UI e threads em funcionamento.

Page objects são geralmente usados para testar, mas também pode ser usados para providenciar uma interface de scripts sobre uma aplicação. Geralmente é bom ter uma interface script por debaixo da UI – o que é mais rápido e mais seguro. Entretanto, com uma aplicação que tem muitos comportamentos na UI, usar page objects pode ser a melhor ajuda em um trabalho ruim – mas tente mover a lógica se possível, será melhor tanto para os scripts quanto para uma UI saudável por mais tempo.

É comum escrever testes usando alguma Linguagem Específica de Domínio (DSL), tal como Cucumber ou outra DSL interna. Se for o seu caso, é melhor arranjar sua DSL de testes para usar os page objects, permitindo você ter um parser que traduza suas chamadas a DSL em chamadas aos page objects.

Caso você tenha chamadas a um WebDriver em seus testes, você esta fazendo isso errado – Simon Stwart.

Padrões que digam para mover a lógica para fora dos elementos UI (tal como Presentation Mode, Supervising Controller ou Passive View) tornam menos úteis os testes na UI e assim, reduzem a necessidade dos page objects.

Page objects são um exemplo clássico de encapsulamento – eles ocultam detalhes da estrutura do UI e a componentização de outros componentes (e testes). É um bom princípio de design procurar situações como essa enquanto você desenvolve – perguntando a você mesmo “como eu posso ocultar alguns detalhes do resto do software?”. Como em qualquer encapsulamento, isto envolve dois benefícios. Eu tenho ressaltado que você deve colocar a lógica que manipula a UI em um único lugar onde você pode mudar sem afetar outras partes do sistema. Um benefício consequente disso é que isso permite ao cliente testar um código mais fácil de ser entendido, uma vez que a lógica ali é sobre a intenção do que se ter testar, não relacionando a detalhes de UI.