1, 2, 3, testando…

Testar é um passo obvio na escrita de código. Sempre que terminamos de escrever (ou enquanto ainda estamos escrevemos), executamos o código para verificar se o resultado esperado está sendo alcançado. Afinal, um código que não executa ou não gera o resultado, não serve pra nada.

Acredito que a maioria, começa simplesmente executando o código (abrindo a página no browser, compilando e executando pela IDE ou símplesmente fazendo uma chamada via cli) e verificando manualmente o resultado. Quando o resultado não corresponde, adicionamos mais informação, via log, ferramentas de debug ou uma exibição de informações própria da linguagem (como var_dump em PHP) e procuramos o problema, ou onde o que deveria ter sido feito não aconteceu.

Como todo bom preguiçoso, clicar em uma pagina ou IDE começa a ficar chato depois de um tempo, principalmente quando se necessita de interação para chegar onde se quer testar. O que acontece quando seu software cresce? Quando seu código não é mais um script de 300 linhas e sim um emaranhado de classes e chamadas entre elas?

Testando código com código

Para facilitar os testes durante a escrita de código, podemos utilizar código para testar código, ou seja, executamos o nosso código, capturamos o resultado e validamos, utilizando tambem código. Um exemplo bastante simples em PHP:

<?php

function soma($num1, $num2) {
    return $num1 + $num2;
}

$resultado = soma(1, 1);
if ($resultado != 2) {
    die("Resultado da soma errado");
}

Por que fazemos isso? Alguns dos meus motivos são:

Conforme o código cresce, uma opção é separar os testes, e testar partes menores por vez, e não somente o todo de uma unica vez.

Testes unitários

Um dos tipos de teste é o teste unitário, ou seja, um teste de unidade. Podemos definir uma unidade como o menor pedaço de código que podemos testar. A unidade mais utilizada para OOP são metodos de classe.

A idéia é uma checar pedaços pequenos de código, o que pode facilitar o debug, acelerar a execução do seu teste (quando a execução do código completo é relativamente lenta e você precisa testar apenas uma chamada, por exemplo) e isolar o código, evitando que um erro inserido em um determinado código seja interpretado como um erro em outro lugar (se a função X está retornando um valor incorreto mas tudo o que você percebe é um comportamento inesperado na função Z).

Outro benefício é que podemos aumentar as opções de teste, exercitando nosso código de diversas outras maneiras, e não só mais o “caminho feliz”. Podemos verificar se nosso código realmente filtra as entradas, valida os valores e executa o comportamento condicional correto. O que é um benefício, também pode ser tornar um malefício quando o nosso código só falha quando não isolado, ou seja, quando chamado em conjunto com outro pedaço de código. Ai entram os testes de integração.

Testes de integração

Testes de integração são exatamente o oposto de testes unitários. O objetivo é garantir que o resultado é atingido quando todo ou parte do código interage, e é utilizado em conjunto. Porém, os limites não são necessáriamente definidos. Podemos testar a integração entre duas funções, quatro metódos, seis classes, ou mais de um recurso (banco de dados, API, etc.).

Qual é melhor?

Aquele que é feito. Ambos tem seu valor e são aplicados por razões diferentes mas um não substitui o outro. Os testes unitários geram grande confiabilidade no código escrito, porém, não tem como garantir o mesmo resultado quando outra parte do código muda. Principalmente quando essa outra parte não está sob o controle do desenvolvedor. Os códigos de integração podem verificar essa interação, porém, podem se tornar muito lentos em diversos casos.

Outros tipos de teste

Os testes unitários e de integração não são os únicos tipos de teste disponiveis. Existem diversos outros, lembrando que os testes que escrevemos, muito provavelmente, acabam sendo de mais de um tipo por vez. Alguns tipos são:

Não sou profissional se não testo?

Os testes existem por um objetivo principal: atestar qualidade. Quando escrevemos testes, queremos garantir que nosso código funciona. Podemos verificar se nosso código é robusto e está preparado para quando a situação não é ideal (parâmetros errados, falha de conexão, etc.). Os testes, hoje, talvez sejam a maneira mais facil e comum de se atestar qualidade. A não ser que você tenha outra maneira de fazer isso, escrever testes é um bom sinal de profissionalismo (mas não o garante).

TDD?

Desenvolvimento guiado por testes (Test-driven development, ou TDD), é um processo de se escrever testes antes do próprio codigo ser escrito, o que, supostamente, força o desenvolvedor a refletir sobre o código e por resultado, escreve um código de melhor qualidade. O real benefício do TDD é bastante discutivel, principalmente pelo fato de qualidade ser um atributo bastante subjetivo. Porém, é uma discussão que não cabe nesse post.

Um ponto importante é que, principalmente conforme nossa experiencia aumenta, não necessáriamente precisamos escrever esse teste antes para obter os beneficios. Muitas vezes, antes de começar, já temos uma ideia do que código que queremos escrever e conseguimos guiá-lo a uma melhor qualidade. O que acaba por ser um processo de escrever os testes simultaneamente, nem antes, nem depois.

Por Pedro Fornaza

Desenvolvedor de software há mais de 10 anos. Formado em Sistemas de Informação. Empreśario. Trabalha principalmente com CRM e projetos Web.