Testes de Aceitação com Capybara / RSpec e Page Objects

Já abordei um pouco sobre testes unitários com mocks. Particularmente não tenho nenhuma preferência em fazer testes da forma mockista ou da forma classicista, creio que as duas formas são interessantes e servem à propósitos distintos. Enquanto uma está preocupada com a forma como os objetos colaboram entre si, a outra está preocupada no resultado final. Ainda com relação a quantidade de colaboradores com as quais os objetos se preocupam, podemos chama-los de testes unitários, de integração, de aceitação e muitos outros nomes.

Em programação orientada à objetos, um teste unitário se preocupa com apenas um objeto, ele testa apenas o comportamento daquele objeto, no entanto isto não é uma regra para ser levada ao pé da letra. Alguns testes, tidos como unitários, acabam testando um pouco além das fronteiras do próprio objeto ou da própria unidade à ser testada.

Existe uma discussão muito grande na comunidade sobre as vantagens de se realizar testes unitários da forma mockista X a forma classicista. Quando temos um sistema onde muitos objetos colaboram entre si, uma forma de se testar apenas um objeto é mockando ou criando falsamente os objetos colaboradores, fazendo com que o teste só exercite a unidade que de fato deve ser testada. Ao usar os objetos colaboradores reais o teste unitário acabará por testar todos os objetos colaboradores e isso se caracterizará como um teste de integração entre os objetos e não mais um teste puramente unitário. Como disse a discussão é muito grande e não pretendo incita-la aqui.

Mas um sistema não é composto só de testes unitários. É necessário que existam testes com um nível mais alto de abstração. No caso de um sistema web o nível mais alto de abstração é testar a funcionalidade no browser, como se fosse um usuário. Existem várias ferramentas para automatizar este processo e em ruby/rails uma das mais populares é a gem Capybara que é usada em conjunto com RSpec para gerar testes chamados de aceitação, ou que simulam o caso de uso como um usuário deve usá-lo, de forma automática. O Capybara em conjunto com RSpec facilita e muito a criação de testes automatizados com o browser mas esses testes podem rapidamente se tornar uma bagunça se não adotarmos táticas e metodologias para reaproveitamento de código, aqui é que entra o padrão page object.

O padrão Page Object é uma excelente forma de se obter reusabilidade nos seus códigos de testes com browser. Normalmente quando escrevemos testes relacionados à interações com elementos html ou javascript, o código tende a se tornar muito acoplado à página à ser testada. Com Page Objects podemos criar abstrações que acabam por se tornar uma API do caso de uso e escondem a complexidade das APIs para acesso aos campos de um formulário ou tabela por exemplo. Com este padrão podemos também reutilizar o Page Object em outros métodos sempre acessando a sua API, tornando os testes bem mais simples e fáceis de serem lidos. Um outro fator importante é que se mudarmos uma página específica só teremos que mudar em um local nos nossos testes.

Como Martin Fowler cita em seu famoso texto sobre este padrão:

The basic rule of thumb for a page object is that it should allow a software client to do anything and see anything that a human can. It should also provide an interface that’s easy to program to and hides the underlying widgetry in the window. So to access a text field you should have accessor methods that take and return a string, check boxes should use booleans, and buttons should be represented by action oriented method names. The page object should encapsulate the mechanics required to find and manipulate the data in the gui control itself. A good rule of thumb is to imagine changing the concrete control — in which case the page object interface shouldn’t change.

O padrão page object, não necessariamente necessita representar uma página, pode representar um elemento complexo de uma página ou um elemento que se repete em várias páginas. Pode ser usado também para testes de desktop em frameworks como Java/Swing e outros. Um Page Object não deve contem nenhum tipo de assert sendo sua única responsabilidade representar uma página ou um objeto de página mais complexo. É bom que seus métodos retornem atributos como string, date, boolean ou um outro page object.

Para demonstrar o uso de page objects eu preferi mostrar um caso CRUD já que é facilmente entendido por todos e é um caso que apesar de simples, consegue demonstrar o poder de reusabilidade e clareza que o padrão page object nos entrega. É claro que você pode optar por fazer testes mais rigorosos do que estes aqui apresentados, mas a intenção aqui é mostrar o uso do padrão e não, ser o exemplo perfeito de testes de software.

Aqui está o Page Object da página de Login:

Começando com o arquivo de testes do RSpec. Neste arquivo estão os testes de crud:

Este é o Page Object da tela de listagem. Note que o código de mais baixo nível que seria o código de acesso aos elementos de página e código para navegar entre as páginas ou para ir para algum path estão encapsulados em métodos que possuem nomes mais claros. O ideal é testar se todos os elementos que o caso de uso pede estão na tela, mas neste exemplo, só para demonstrar eu verifico, somente, a existência do cep. Note também que os métodos retorna outra página quando há um comportamento que redireciona para uma nova página.

A mesma coisa acontece neste Page Object para a tela de novo registro:

Aqui está o Page Object de edição:

Não existe uma regra básica do que colocar em um Page Object a não ser que os métodos de um page object devem retornar strings, boolean, dates e etc ou um outro page object. Algumas pessoas acham que é melhor colocar as assertions dentro dos page objects evitando assim a duplicação de asserts nos testes. Eu, particularmente, acho que um page object deve encapsular o código de mais baixo nível para acesso à uma página ou componente complexo e os asserts devem permanecer onde eles deveriam estar, ou seja, no próprio teste.

Se você curtiu clica no coração abaixo. Valeu!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.