Testes e qualidade de código

Testes unitários, integração, UI e pirâmide de testes

Ao estudar desenvolvimento, há um obstáculo inevitável.

4 min de leitura
Imagem de capa de Testes unitários, integração, UI e pirâmide de testes

Ao estudar desenvolvimento, há um obstáculo inevitável.

“Teste unitário, de integração, de UI… qual é a diferença?”

Vou começar pela conclusão.

Os três testes têm escopos diferentes. O teste unitário verifica uma função, o de integração conecta módulos e o de UI confere toda a tela do usuário.

A “pirâmide de testes” orienta em que proporção combinar os três. Hoje vou explicar esse conceito com exemplos da minha experiência.


Vamos direto ao resumo principal

Para quem está com pressa, aqui vai o resumo.

  1. Teste unitário: verifica uma função ou classe. É rápido e deve ser escrito em grande quantidade.
  2. Teste de integração: verifica se vários módulos funcionam quando conectados. Quantidade intermediária.
  3. Teste de UI: valida o fluxo completo como se a tela real estivesse sendo clicada. É lento e deve ser limitado.
  4. Pirâmide de testes: princípio de construir uma base ampla de testes unitários e um topo estreito de UI.

Só de lembrar dessas quatro linhas, você já entendeu metade. Agora vamos destrinchar cada ponto.


Testes unitários, de integração e de UI: qual é a diferença?

Como essa é a parte mais confusa, vou começar com uma analogia.

Imagine que estamos construindo um carro.

O teste unitário verifica se um parafuso atende às especificações. É uma unidade bem pequena.

O teste de integração verifica se o motor e o câmbio se encaixam e funcionam quando conectados.

O teste de UI é entrar no carro pronto, dar a partida e dirigir.

Em uma tabela, a comparação fica assim.

Categoria Escopo da verificação Velocidade Quantidade escrita
Teste unitário Uma função ou classe Muito rápido (ms) Muitos
Teste de integração Integração entre módulos Normal (em segundos) Média
Teste de UI Fluxo completo do usuário Lento (dezenas de segundos) Poucos

A diferença principal é “o quanto você amplia o escopo”.

Quanto mais amplo o escopo, mais próximo ele fica do ambiente real, mas também fica mais lento e difícil de manter.


É assim que os testes unitários funcionam

Explicação sozinha não basta, então vamos ver um exemplo curto.

Abaixo há um teste unitário que verifica apenas uma função responsável por somar dois números.

// Teste unitário que verifica uma única função de soma
func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}

@Test func Soma_2_adição_3é_5() {
    #expect(add(2, 3) == 5)
}

Como você pode ver, não precisamos de banco de dados externo nem de tela. Isolamos e verificamos uma única função.

Por isso a execução termina em um piscar de olhos. Mesmo rodando centenas, leva apenas alguns segundos.

É por essa rapidez que uso mais testes unitários. Posso alterar o código e conferir tudo imediatamente.

Você continua usando testes unitários por causa dessa luz verde de sucesso
Você continua usando testes unitários por causa dessa luz verde de sucesso

O que é a pirâmide de testes?

Agora entra a protagonista de hoje: a pirâmide de testes.

É um conceito apresentado por Mike Cohn em 2009, no livro 『Succeeding with Agile』. A proposta é empilhar os testes em formato de triângulo.

  • Parte inferior (larga): testes unitários — a maioria
  • Parte central: testes de integração — uma quantidade moderada
  • Parte superior (estreita): testes de UI — o mínimo

Por que esse formato?

Porque os testes ficam mais rápidos e baratos quanto mais abaixo estão. Rodar milhares de testes unitários não pesa.

Já os testes de UI são lentos e quebram facilmente com pequenas mudanças na tela. O custo de manutenção é alto.

Muitos testes baratos e rápidos; poucos testes caros e lentos. Isso é toda a pirâmide de testes.

Quando a pirâmide é invertida, temos o antipadrão “cone de sorvete”. Há muitos testes de UI e nenhum teste unitário: testes lentos e frágeis que atrapalham o trabalho.


Então, como definir a proporção?

Essa é uma dúvida comum.

A referência mais citada é aproximadamente 70% unitários : 20% de integração : 10% de UI.

Mas isso não é uma regra absoluta. Ajuste a proporção conforme o projeto.

Em um servidor de API backend, por exemplo, aumentar a participação dos testes de integração é mais prático. Até o Google enfatiza manter o formato de pirâmide, e não um número exato.

Vou acrescentar mais um conselho baseado na minha experiência.

Não fique obcecado pelos números. O importante é criar o hábito de verificar se você depende demais de testes lentos e frágeis.


Perguntas frequentes (Q&A)

P. Testes E2E e testes de UI são a mesma coisa?

Eles são usados de forma quase equivalente, mas tecnicamente são diferentes. E2E (End-to-End) valida o fluxo completo sob a perspectiva do usuário; o teste de UI se concentra na interação com a tela. Na prática, é comum misturá-los.

P. Se eu fizer bons testes de integração, posso dispensar os testes unitários?

Não é recomendado. É difícil identificar exatamente onde surgiu o problema em um teste de integração. Os testes unitários ajudam a restringir a causa rapidamente.

P. Preciso escrever todos os testes desde o início?

Não. Recomendo começar com testes unitários da lógica principal. Já vi muita gente se esgotar tentando construir uma pirâmide perfeita desde o começo.

Base larga, topo estreito: basta lembrar desse formato
Base larga, topo estreito: basta lembrar desse formato

A diferença entre os três pode parecer abstrata no texto, mas fica clara de verdade quando você escreve código.

Comece adicionando um teste unitário a uma função pequena. À medida que essa prática se acumular, o restante virá naturalmente. Boa sorte!