[EN] There is a version of this article in english, you can access it here
Nos últimos anos, grande parte do meu trabalho tem sido ajudar times a ampliar e otimizar suas suítes de testes automatizados. E uma coisa que se repete o tempo todo é o mesmo tipo de problema: os testes até existem, mas são difíceis de entender.
Ninguém sabe exatamente o que está sendo testado, onde estão certos cenários ou se as ramificações lógicas estão realmente cobertas. Como resultado, aparecem buracos de cobertura, testes redundantes e muito tempo perdido tentando entender o que já existe.
Em diversas ocasiões, ao parear com desenvolvedores menos experientes, vejo um padrão se repetir: eles passam um bom tempo rolando o arquivo de testes de cima a baixo, procurando por um código “parecido” com o que querem escrever. A ideia é colocar o novo teste “perto dos outros semelhantes”. Esse hábito é compreensível, mas também um sintoma de um problema estrutural: se você precisa "adivinhar" onde o teste deveria estar, é porque a estrutura do arquivo não está clara o suficiente.
Com o tempo, desenvolvi uma técnica que me ajuda bastante a organizar e visualizar a estrutura dos testes. É simples, prática e aproveita um recurso que praticamente todo editor de texto moderno tem: o folding de código.
Eu chamo essa técnica de Unfolding Tests.
Os exemplos que aparecem neste artigo usam Ruby on Rails e RSpec, mas os mesmos princípios se aplicam a qualquer outro framework de testes.
A ideia por trás do Unfolding Tests
A ideia é usar o “folding” de blocos de código como uma ferramenta de leitura e escrita. No VSCode, por exemplo, você pode dobrar (fold) e desdobrar (unfold) blocos de código como describe, context e it.
Para começar, basta usar o comando Fold All (no macOS: Cmd + Shift + P; no Windows: Ctrl + Shift + P) e digitar “Fold All”.
Essa técnica vem muito da ideia de reduzir a carga cognitiva. Quando tudo está dobrado, você vê apenas o esqueleto do teste, o que permite entender rapidamente o que está sendo testado e como os cenários estão organizados, sem precisar ler detalhes de implementação.
Com isso, o foco passa a ser principalmente a INTENÇÃO, e não cada linha de código.
A partir daí, começo a expandir os blocos aos poucos e com isso passo a entender:
- O que está sendo testado (
describe
) - Quais são os cenários possíveis (
context
) - Quais são as expectativas em cada cenário (
it
) - E quais setups estão sendo usados em cada camada
Essa visão hierárquica me dá uma leitura muito mais clara do comportamento do sistema testado. E o mais interessante é que o mesmo processo funciona também para escrever testes.
Escrevendo testes com Unfolding Tests
Quando começo um novo arquivo de testes, eu não penso nas linhas de código. Penso na estrutura que quero ver dobrada.
Crio primeiro o esqueleto do teste:
RSpec.describe UserPolicy do
context 'when user is admin' do
it 'allows access'
end
context 'when user is not admin' do
it 'denies access'
end
end
Quando esse arquivo está totalmente dobrado, o que vejo é algo como:
UserPolicy
when user is admin
allows access
when user is not admin
denies access
Isso já é suficiente para entender o que está sendo testado e quais são os cenários.
Aliás, essa visualização lembra bastante o output do RSpec quando você usa o formato --format documentation.
Se você ainda não está usando esse formato, deveria. Ele transforma a execução dos testes em uma leitura quase narrativa, mostrando exatamente o que cada teste descreve, na mesma hierarquia que você definiu nos blocos describe, context e it.
Depois disso, vou desdobrando bloco por bloco e preenchendo os detalhes: setups, mocks, expectations e assim por diante.
A hierarquia de setups
Uma das partes mais importantes do Unfolding Tests é respeitar a hierarquia entre os blocos e seus setups.
Abaixo de cada
describe
deve haver um setup com os pré-requisitos gerais para todos os cenários que estão dentro daquele bloco.Abaixo de cada
context
deve haver um setup com os pré-requisitos específicos daquele cenário. Aqui seu setup deve prover as condições para que a descrição do seucontext
seja verdadeira.E o código do teste em si deve estar sempre dentro do bloco
it
, que é o nível mais baixo da estrutura, onde as expectativas são verificadas.
describe 'Listing orders' do
let(:admin_user) { create(:user, :admin) }
before do
sign_in(admin_user)
visit orders_path
end
context 'when there are no orders' do
before { Order.delete_all }
it 'shows the empty state message' do
expect(page).to have_content('No orders found')
end
end
context 'when there are orders' do
let!(:orders) { create_list(:order, 2) }
it 'lists all orders' do
expect(page)
.to have_text(orders.first.id)
.and have_text(orders.second.id)
end
end
end
Se você dobrar esse arquivo, mesmo sem ver os detalhes de implementação do teste, dá para entender o propósito do teste, os cenários que ele cobre e o comportamento esperado em cada caso. E então, ao desdobrar cada bloco, você revela os detalhes necessários: primeiro o setup, depois o teste.
Contexts como ramificações lógicas
Um princípio importante dessa técnica é que cada ramificação lógica merece o seu próprio context
.Se uma variável pode assumir três estados (Ex. full
, partial
, empty
), então você deve ter três contexts, um para cada caso.
Exemplo:
context 'when report is full' do
# ...
end
context 'when report is partial' do
# ...
end
context 'when report is empty' do
# ...
end
Isso ajuda a garantir que os testes realmente explorem todas as possibilidades relevantes.
E mais: para mim, não faz sentido ter um context sem outros que representam outros estados antagonistas. Se existe um context 'when user is admin', então precisa existir outro context 'when user is not admin'. Esses pares deixam claro que o teste cobre ambos os lados da lógica, e isso é fácil de perceber quando o arquivo está dobrado.
Por que isso funciona
O Unfolding Tests transforma o ato de ler e escrever testes em algo visual e incremental.
Você vê a estrutura antes de ver os detalhes, o que ajuda a:
- Entender rapidamente o escopo do arquivo
- Identificar redundâncias e lacunas
- Garantir que cada caminho lógico tem seu par
- Escrever testes que também servem como documentação viva
No fim das contas, u*m bom teste é também uma boa forma de documentação*. E quanto mais clara for a intenção expressa na estrutura, mais fácil será para qualquer pessoa entender o comportamento esperado do sistema.
Dicas para começar a aplicar
Dobre tudo (
Fold All
).
Comece com o arquivo de testes completamente dobrado. Isso te dá uma visão geral da estrutura, dos blocos principais e dos cenários existentes.Vá desdobrando gradualmente.
Expanda primeiro os blocosdescribe
para entender o que está sendo testado. Depois abra oscontext
para ver os cenários e, por fim, osit
para olhar as expectativas. Essa progressão te permite entender o teste camada por camada, sem sobrecarregar a mente com detalhes desnecessários logo de início.Verifique se a estrutura faz sentido dobrada.
Se, com tudo dobrado, você não consegue entender o que o arquivo testa ou quais cenários cobre, é sinal de que a estrutura precisa ser revista.Ao escrever novos testes, pense primeiro na estrutura.
Monte o esqueleto comdescribe
,context
eit
antes de escrever o código.Use
context
para expressar variações lógicas.
Sempre que possível, escreva contexts em pares — por exemplo, “when user is admin” e “when user is not admin”.Respeite a hierarquia dos setups.
Use obefore
e olet
geral dentro dodescribe
, e setups específicos dentro de cadacontext
.Só então escreva o conteúdo dos testes (
it
).
Depois que a estrutura e os pré-requisitos estiverem claros, adicione o código do teste em si.
O Unfolding Tests é uma forma simples de trazer clareza e intenção para os testes.
Ele força você a pensar na estrutura antes dos detalhes e a tratar cada cenário como parte de um todo coeso. No fim, o benefício é duplo: os testes ficam mais fáceis de entender e o código fica mais difícil de se perder em meio a casos confusos ou redundantes.
Se você costuma se perder em arquivos grandes de teste, experimente dobrar tudo e ir desdobrando aos poucos. É uma técnica muito simples mas é impressionante como isso muda a maneira de ler e escrever testes.
Top comments (0)