[tweet]Software bom, que atende ao negócio com custo apropriado, demanda boas práticas de engenharia de software.[/tweet] Dentre essas práticas, destaca-se, sem dúvidas, o desenvolvimento de testes automatizados. Entretanto, não podemos ignorar o fato de que estes custam tempo e dinheiro, afinal, são códigos que precisam ser produzidos e mantidos. Quando são mal feitos, não compensam o investimento.
Testes difíceis de entender, por exemplo, aumentam o tempo que o programador precisa para fazer ajustes em uma base de código. Além disso, quando acusam falha, não ajudam a detectar rapidamente como resolver o que há de errado. Ou seja, mesmo que tenham valor por evitar erros em produção, poderiam agregar ainda mais.
Em bases de código C# não é raro encontrar testes verificando o funcionamento dos getters e setters. Entretanto, convenhamos que esse funcionamento é garantido pela Microsoft e, seguramente, já foi testado por seus programadores.
public class Customer { public string Name { get; set; } // .. } /* ------------------------------------- */ public class CustomerTests { public void GetterAndSetterWorkForNameProperty { var c = new Customer(); c.Name = "John Doe"; Assert.Equal("John Doe", c.Name); } }
Há também aqueles testes que, embora adicionem algum valor, quebram facilmente durante a evolução do sistema. Em suma, são testes frágeis com alto custo de manutenção. Por exemplo, testes de construtores que inicializam propriedades de uma classe.
public class CreateUserCommand { public CreateUserCommand(string name) { Name = name ?? throw new ArgumentNullException(nameof(name)); } public string Name { get; } } /*-------------------------*/ public class CreateUserCommandTests { [Fact] public void UserNameIsMandatory() { Assert.Throws(() => new CreateUserCommand(null)); } }
[tweet]Testes ruins valem menos que o espaço que consomem nos dispositivos de armazenamento.[/tweet] Mais que isso, são também dívidas técnicas pois geram impacto negativo para o negócio e para os times técnicos.
De forma objetiva, [tweet]o custo para desenvolver e manter software com testes deve ser menor do que seria se não houvesse teste algum.[/tweet] Quando não é assim, há algo muito errado.
Bons testes protegem contra regressão, dão segurança para atividades de refatoração, contribuem para a redução do lead time e reduzem os custos de manutenção. [tweet]Com o tempo, boas bases de testes também ajudam a previnir erros, mas este é apenas um efeito colateral positivo.[/tweet]
Testes podem ser usados apenas para demonstrar a presença de bugs, nunca a ausência! – Edsger W. Dijkstra
Faltou adicionar exemplos de testes bons e como chegar neles.
Elemar, seria interessante nós apresentar bons testes. As vezes eu sinto que escrevo testes desnecessários onde só existe custo para o projeto. Essa parte do seu texto ficou muito ubscura “Testes ruins valem menos que o espaço que consomem nos dispositivos de armazenamento.”, cknsegue na explicar?
Confesso que o tema testes é uma coisa que me deixa com bastante dúvida. Sempre ouvi que teste bom é aquele que quebra quando alguma parte razoável é alterada. Se não quebra pode ser uma baixa cobertura ou teste mal feito que apenas testou cenários de sucesso e não o de erro, deixando um bug silencioso no código. Na experiência de vocês isso faz sentido ou a perspectiva na hora de criar os testes deve ser outra?
Everton você citou duas categorias essenciais para um teste de qualidade que são “Protection against regression” e “Resistance to refactory”. Na minha experiência, proteger o código de qualquer regressão é inegociável, logo todo teste deve de alguma forma proteger o System Under Test de regressões. Entretanto, o post acima tem como principal objetivo provoca-los a observar que escrever testes sem o devido cuidado é custo.
Olá Mail Braga,
A ideia deste trecho é passar a percepção que um teste quando mau escrito é somente custo para o seu projeto.
Obrigado.
Olá Ismael, obrigado pelo seu feedback.