Testes unitários / Mocks são realmente necessários?

Bill Burke fez um barulho no post sobre JavaEE X Spring, mas o que muitas pessoas não notaram é que teve uma discussão intensa nos comentários
sobre a necessidade de se fazer testes unitários.

Uma das opiniões dos leitores, que Bill Burke disse concordar completamente, é essa

“…Test in the real environment and get results that are truly valid. Stop kidding yourself with mocks…”

A discussão foi tão grande, que ele acabou de lançar um post sobre mocks!

No post ele volta a discutir a necessidade de teste unitário e integração.

E o que você acha? Vale a pena investir em testes unitários ou ficar só com testes de integração e fazer o uso de ferramentas como o Arquillian?

Vix, este topico vai gerar mta discussao :slight_smile:

Mas com certeza TUDO a favor de testes unitarios.

Cara, eu nao sei mais o que é desenvolver sem escrever pelo menos um teste com cenario ideal pra aquela funcao. Imagina toda vez que for gerar uma release, vc ter que ficar fazendo TODOS os testes funcionais, passando por todas as telas e todas as funcionalidades? Ai de repente acha um erro (nunca acha erros né? rs) e tem que fazer os testes tudo de novo, para ver se essa solucao nao quebrou nada.

Inumeras vezes meus testes e de outras pessoas foram quebrados, por coisas que eu nao tinha nem nocao que podia quebrar. Imagina se vc, em um projeto JEE, usa maven e jboss, ai toda vez que fizer uma alteracao, vc tem que recompilar o projeto pelo maven e subir o jboss pra testar apenas uma funcionalidade. Bem mais rápido vc escrever um teste unitário (que ficara pra sempre no projeto) e rodar pra ver se realmente funciona.

Imagina chega um estagiario novo, e faz alteracao em um ENUM, colocando um registro no meio, e no sistema, tinha outro estagiario (que ja saiu da empresa) que fez a funcionalidade pelo ordinal do enum. Aparentemente está OK, depois de 1 ano, vc ve que o sistema tava salvando tudo errado. Mas e agora? E pra saber desde quando o sistema está gravando errado? Pensa no tempo e no custo que isso vai custar ao projeto.

Testes unitarios é totalmente necessário para um desenvolvimento de software. Nao estou falando isso porque li a respeito, mas sim porque vi a diferenca e a necessidade na prática.

O ideal é no momento que estiver criando o projeto, nao passar pra outra camada sem escrever testes unitarios pra ele antes. Pq se vc for fazer todo o sistema, pra depois comecar a escrever os testes, “nao vai dar tempo” de escrever, e vai acabar ficando com menos prioridade.

Testes Unitários são independentes dos testes de integração assim como estes são independentes de dos testes de aceitação.

Testes unitários podem ser vistos como uma forma de projeto, aplicando TDD ou simplesmente de garantir que uma pequena parte do sistema funcione.

A industria faz isso a banstante tempo utilizando-se de Pokas-Yokes para garantir que parte da montagem das peças que compõem um produto não não sejam feitas de maneira inadequada. Isso não elemina os testes finais com o produto acabado mas evita grandes problemas como danos ao produto ou ter que desmontar todo um produto para corrigir um problema e pode evitar que um problema seja encotrado só no cliente.

Para nós o problema de só fazer testes de integração ou aceitação é que alguns problemas podem passar se só ser pegos em produção e mesmo que seja encontrado uma falha nesses testes demora-se muito mais para corrigi-los do que desenvolver um teste um unitário.

Testes unitários também facilitam a refatoração, pois dão um feedback rápido para o programador sobre as mudanças efetuadas.

Os testes unitários são importantes tanto quanto os outros, pois erros encontrados nas fases preliminares são bem mais rápidos de serem corrigidos do que os somente descobertos na fase de aceitação, por exemplo. Ainda, acredito não ser útil/necessário fazer mocks para todos os processos, pois é dispendido um tempo a mais somente para fazê-los.

Não entendo essa idéia de que existe uma regra geral sobre quais testes fazer, quais deixar de lado.

Testes são uma ferramenta e como tal deve ser usado conforme o caso.

Se você não sabe o melhor para o seu caso não vai ser um blogueiro na net que vai saber.

Quando possível eu gosto de utilizar objeto real. Para teste de DAO por exemplo, eu gosto de utilizar HSQLD. O DAO irá se comportar como realmente deve.

Agora, se você tem uma classe que faz cobrança de cartão de crédito a um cliente… como você vai fazer se não tiver um mock? Ou algum simulador?

Acho necessário sim o mock, mas não para todas as situações.

É como este mesmo pensamento que testes são perca de tempo e a coisa é desenvolver, eu já vi muita mas muita merda mesmo acontecendo, dai o tempo para achar a merda e corrigir é bem maior do que se o cara tivesse perdido um tempinho nos testes unitários e mocks…

Em questão de software tem que se levar Murph a serio, se não meu amigo vc ta f*****.

Provavelmente a maioria das pessoas que acha testes unitários desnecessários é a maioria que considera análise e design de um sistema como algo totalmente fútil. Documentação, então, nem se fala. Já pensaram em uma especificação de caso de uso sem fluxos alternativos ou de exceção?
Eu sou sincero em falar que acho testes um saco, porém, admito que sem eles é impossível garantir qualidade no produto que se desenvolve.
Nenhum software está 100% testado, pois por mais que se pense em 200 possibilidades diferentes, pode ocorrer a 201ª e tudo ir por água abaixo.
São riscos, mas, quanto mais testes realizados, menores eles são.
E isso inclui os testes unitários.

Não imagino mais meu mundo sem mocks ou teste unitários :slight_smile:

+1

Eu também penso assim, mas sempre evitando o uso excessivo de mocks, preferindo sempre um objeto com comportamentos reais.

Testes de unidade são importantes para garantir regras de negócio com maior corretude. Então tem de tomar cuidado pra não sair criando testes para toda e qualquer classe do sistema; testes de unidade tem custo e devem ser utilizados em classes que tem maior prioridade para serem testadas (classes de maior valor do ponto de vista de negócio).
O problema que tem muito desenvolvedor que considera todos os métodos do sistema uma unidade de teste.

[quote=AlexandreGama][quote]
Não imagino mais meu mundo sem mocks ou teste unitários
[/quote]

+1[/quote]

Trabalhei em um lugar em que aprendi a automatizar os testes de integração (eles não faziam automação de testes unitários, mas não impediam você de fazer), achava fantástico a segurança que ele dava em mudanças futuras e ao mesmo tempo entendia que a cada teste criado, seria mais um código a manter, o que se não fosse feito adequadamente seria apenas mais um ponto crítico do que uma ajuda. Até ai tudo bem, peguei o ritmo e chegamos ao ponto de ter no mímino 80% de cobertura de testes, e testes com finalidades concretas que ajudavam… Não era TDD mas ainda em certos momentos ajudava até mesmo no design da aplicação.

O problema, é que depois que sai de la, nunca mais achei em outro ambiente interesse em automação de testes, e nos lugares que tentei fazer eu senti até uma marginalização por parte dos demais. Até certo ponto entendi, por que o tipo de sistema desenvolvido por essa empresa, era menor e com ciclo de vida bem menor (durava 3, 4 meses no máximo), mas agora estou em outra empresa que tem um produto que deve durar anos, e que será o carro chefe da empresa, está em fase final de desenvolvimento, e nada foi construído baseado em testes, ou com algum suporte para isso. Temos apenas um ou outro aventureiro que tenta escrever algo que ele ache util em algum momento, mas não é a regra. Nesse caso, o projeto que já está atrasado, e muito. Parece ser muito frágil quanto a mudanças, é fácil perceber que se em certo ponto alguém adicionar algo, pode quebrar outros pontos. Como entrei com o projeto andando, confesso que tenho medo de alterar partes do sistema (Aqui lembro do XGH) sem a segurança que tinha antes.

Quanto ao TDD e uso de mocks em si, eu não usei tão fortemente, mas eles devem ser muito uteis em caso que vc dependa de algo que ainda não tenha acesso, ou ainda para evitar o carregamento de uma série de coisas que não seriam interessantes apenas para validar uma lógica.

[quote=drsmachado]Provavelmente a maioria das pessoas que acha testes unitários desnecessários é a maioria que considera análise e design de um sistema como algo totalmente fútil. Documentação, então, nem se fala. Já pensaram em uma especificação de caso de uso sem fluxos alternativos ou de exceção?
Eu sou sincero em falar que acho testes um saco, porém, admito que sem eles é impossível garantir qualidade no produto que se desenvolve.
Nenhum software está 100% testado, pois por mais que se pense em 200 possibilidades diferentes, pode ocorrer a 201ª e tudo ir por água abaixo.
São riscos, mas, quanto mais testes realizados, menores eles são.
E isso inclui os testes unitários.[/quote]

A idéia de que testes unitários servem para criar software infalível (qualidade é quando o software é entregue no prazo e fazendo apenas o que o cliente pediu) é discutível já que esses testes são escritos por pessoas, e estes estão sujeitos a falha ou má compreensão do problema.

Pra mim testes servem mais como documentação, e como tal podem ser úteis, principalmente em ambientes com alta taxa de rotatividade de progamadores.

[quote=jakefrog]Quando possível eu gosto de utilizar objeto real. Para teste de DAO por exemplo, eu gosto de utilizar HSQLD. O DAO irá se comportar como realmente deve.

Agora, se você tem uma classe que faz cobrança de cartão de crédito a um cliente… como você vai fazer se não tiver um mock? Ou algum simulador?

Acho necessário sim o mock, mas não para todas as situações.[/quote]

A operadora de cartão fornece simuladores.
Trabalhei em um sistema onde tínhamos que simular operações cartões de débito, bastava apontar pro servidor de testes e a operação era mockada pela operadora, não por nós, exatamente com o mesmo protocolo e toda a chatice.
Não sei dizer mais detalhes a respeito pq não fui eu quem desenvolveu isso, era manutenção apenas.

Concordo com você em parte sobre isso. Claro que se o desenvolvedor entendeu errado e não é “bem aquilo” que o cliente queria o projeto esta errado. Mas aquilo que você fez, mesmo não atendendo a necessidade do cliente é funcional.

Qualidade é mais do que isso. Eu posso entregar um sistema no prazo que faz o que o cliente queria mas tão cheio de gambiarras que se eu alterar uma linha o sistema todo deixa de funcionar.

Os testes podem ser usados como documentação, mas são mais do que isso! Eles visam favorecer principalmente a evolução gradativa do sistema, garantido que ao realizar uma alteração eu não vou “quebrar” nenhuma funcionalidade. Eles são fundamentais para refactoring!

Escrever testes unitarios eh bastante dificil, ao contrario do que se tenta propagar por aí. Todos os programadores que conheci (pessoalmente) e diziam não gostar de testes unitários, ou que eram trabalhosos ou não compensavam, pecavam na verdade não na hora de fazer o teste, mas nos conceitos básicos de orientação a objetos. Classes extremamente acopladas, com muita responsabilidade, com acesso a dados misturado com regra de negocio e assim por diante.

Por isso quando vão testar precisam fazer uso excessivo de mock, o que complica ainda mais o que já não é simples. Os mocks são para testar fronteiras e existem menos fronteiras do que regra de negócio. Se voce precisa de um mock para testar uma regra há algo errado com sua aplicação. Voce só vai precisar de mock para testar a reação do seu código com as fronteiras do sistema. Logo, se você tem essas fronteiras espalhadas para todo lado, a culpa nao eh dos testes.

Programar com teste é mais produtivo, mais seguro e mais divertido. Se alguém gosta de programar e não gosta de escrever teste unitário, pode ter certeza que é porque não aprendeu ainda a programar com testes. E existem programadores extraordinários, com enorme conhecimento de arquitetura de máquina, conhecimento de baixo nível, conhecimento da plataforma que desenvolvem, de otimização de algorítimo e coisas do gênero e que mesmo assim não são bons designers de código.

Por isso eu repito, se voce não gosta de teste unitário é porque ainda não se deu ao trabalho de estudá-lo a fundo. É muito mais divertido programar com testes. E quanto aos mocks, que eu também não gosto, eles são exceção, não regra, para testes unitários.

Já usei muito mock em testes, mas hoje penso várias vezes antes de usar. Com o passar do tempo, a manutenção de testes com mock acaba ficando cada vez mais complicada e começo a duvidar da eficácia dos mesmos. Claro que existem casos (integração com sistemas de terceiros por exemplo) em que você acaba sendo obrigado a usar mocks, a não ser que possua um simulador do sistema.

Hoje prefiro que os testes sejam os mais reais e próximos da realidade possíveis, ou seja, de integração mesmo.

[quote=LucianoM86]Claro que existem casos (integração com sistemas de terceiros por exemplo) em que você acaba sendo obrigado a usar mocks, a não ser que possua um simulador do sistema.
[/quote]

No final das contas esse simulador do sistema acaba atuando como um mock.

O problema no final das contas não são os mocks, mas o mesmo de todos os outros recursos: a péssima utilização (design patterns que o diga).

Ia dizer aqui o mesmo que falo sobre o Singleton: use apenas na presença de um adulto responsável. Mas pensando melhor, acabaria dizendo o mesmo pra programação como um todo.
O povo descobre um recurso novo e quer sair enxutando cada canto da p* do sistema com isso, de todo modo possível.
Calma ae galera, cada coisa no seu lugar pombas!

[quote=LucianoM86]Já usei muito mock em testes, mas hoje penso várias vezes antes de usar. Com o passar do tempo, a manutenção de testes com mock acaba ficando cada vez mais complicada e começo a duvidar da eficácia dos mesmos. Claro que existem casos (integração com sistemas de terceiros por exemplo) em que você acaba sendo obrigado a usar mocks, a não ser que possua um simulador do sistema.

Hoje prefiro que os testes sejam os mais reais e próximos da realidade possíveis, ou seja, de integração mesmo.[/quote]
Concordo. No início do projeto os mocks são mais produtivos, justamente pelo fato de poderem simular situações que ainda não estão totalmente implementadas. Já com o sistema implementado acho que o mais produtivo é realizar os testes das fases posteriores (sistema, aceitação, etc), que permitem verificar se o que deveria funcionar ainda está funcionando e o que devia ser feito realmente está sendo feito.