Resolvi, por conta própria, criar um simples projeto para controle de ho-
ras de trabalho (eu precisava de um motivo para experimentar todas as
coisas que estava aprendendo naquele momento e, dentre elas, testes au-
tomatizados). O sistema era bem simples: cadastro de funcionários, ca-
dastro de projetos, ligação entre um funcionário e um projeto e cadastro
de horas em um projeto.
Ao final da implementação, apresentei o sistema ao diretor da empresa.
Ele adorou, e me sugeriu a implementação de uma simples regra de ne-
gócio: se o número total de horas colocadas no projeto ultrapasse um
determinado limite, nenhum funcionário poderia adicionar mais horas
nele.
A implementação era bem trivial: bastava fazer um if. Lembro-me que
implementei a regra de negócio e então escrevi o teste de unidade para
garantir que havia implementado corretamente. O teste que acabei de
escrever ficou verde, mas três ou quatro testes que já existiam ficaram
vermelhos. A única linha de código que escrevi fez com que funcionali-
dades que já funcionavam, parassem de trabalhar corretamente.
Naquele momento me veio a cabeça todas as vezes que escrevi uma ou
duas linhas de código, aparentemente simples, mas que poderiam ter
quebrado o sistema. Percebi então a grande vantagem da bateria de tes-
tes automatizados: segurança. Percebi o como é fácil quebrar código, e
como é difícil perceber isso sem testes automatizados. Daquele dia em
diante, penso duas vezes antes de escrever código sem teste.
15
2.4. Continuando a testar
Casa do Código
2.4
Continuando a testar
Ainda são necessários muitos testes para garantir que a classe MaiorEMenor funci-
one corretamente. Nesse momento, o único cenário testado são produtos em ordem
decrescente. Muitos outros cenários precisam ser testados. Dentre eles:
Produtos com valores em ordem crescente
Produtos com valores em ordem variada
Um único produto no carrinho
Conhecendo o código da classe MaiorEMenor, é possível prever que os cenários
acima funcionarão corretamente. Escrever testes automatizados para os cenários
acima pode parecer inútil nesse momento.
Entretanto, é importante lembrar que em códigos reais, muitos desenvolvedores
fazem alterações nele. Para o desenvolvedor que implementa a classe, o código dela
é bem natural e simples de ser entendido. Mas para os futuros desenvolvedores que
a alterarão, esse código pode não parecer tão simples. É necessário então prover
segurança para eles nesse momento. Portanto, apesar de alguns testes parecerem
desnecessários nesse momento, eles garantirão que a evolução dessa classe será feita
com qualidade.
Apenas para exemplificar mais ainda, vamos escrever mais um teste, dessa vez
para um carrinho com apenas 1 produto. Repare que nesse cenário, é esperado que
o maior e menor produtos seja o mesmo:
using NUnit.Framework;
[TestFixture]
public class TestaMaiorEMenor
{
[Test]
public void ApenasUmProduto()
{
CarrinhoDeCompras carrinho = new CarrinhoDeCompras();
carrinho.Adiciona(new Produto("Geladeira", 450.0));
MaiorEMenor algoritmo = new MaiorEMenor();
algoritmo.Encontra(carrinho);
16
Casa do Código
Capítulo 2. Testes de Unidade
Assert.AreEqual("Geladeira",
algoritmo.Menor.Nome);
Assert.AreEqual("Geladeira",
algoritmo.Maior.Nome);
}
}
Comparando só o nome?
Ao invés de comparar apenas o nome do produto, você poderia comparar
o objeto inteiro: Assert.AreEqual(produto, algoritmo.Menor);, por
exemplo. Mas, para isso, o método Equals() deve estar implementado
na classe Produto.
Em certos casos, essa solução pode ser mais interessante, afinal você com-
parará o objeto inteiro e não só apenas um atributo.
2.5
Conclusão
Desenvolvedores gastam toda sua vida automatizando processos de outras áreas de
negócio, criando sistemas para RHs, controle financeiro, entre outros, com o intuito
de facilitar a vida daqueles profissionais. Por que não criar software que automatize o seu próprio ciclo de trabalho?
Testes automatizados são fundamentais para um desenvolvimento de qualidade,
e é obrigação de todo desenvolvedor escrevê-los. Sua existência traz diversos bene-
fícios para o software, como o aumento da qualidade e a diminuição de bugs em
produção. Nos próximos capítulos, discutiremos sobre como aumentar ainda mais
o feedback que os testes nos dão sobre a qualidade do software.
17
Capítulo 3
Introdução ao Test-Driven
Development
Desenvolvedores (ou qualquer outro papel que é executado dentro de uma equipe
de software) estão muito acostumados com o processo tradicional de desenvolvi-
mento: primeiro a implementação e depois o teste. Entretanto, uma pergunta inte-
ressante é: Será que é possível inverter, ou seja, testar primeiro e depois implementar?
E mais importante, faz algum sentido?
Para responder essa pergunta, ao longo deste capítulo desenvolveremos um sim-
ples algoritmo matemático, mas dessa vez invertendo o ciclo de desenvolvimento:
o teste será escrito antes da implementação. Ao final, discutiremos as vantagens e