O teste de TDD e de unidade parece ser a grande rave no momento. Mas é realmente útil em comparação com outras formas de teste automatizado?
Intuitivamente, eu acho que o teste de integração automatizado é muito mais útil que o teste de unidade. Na minha experiência, a maioria dos erros parece estar na interação entre os módulos, e não tanto na lógica atual (normalmente limitada) de cada unidade. As regressões também aconteciam frequentemente devido à alteração das interfaces entre os módulos (e às alterações pré e pós-condições).
Estou entendendo mal alguma coisa ou por que o teste de unidade está recebendo tanto foco em comparação com o teste de integração? É simplesmente porque se supõe que o teste de integração é algo que você tem, e o teste de unidade é a próxima coisa que precisamos aprender a aplicar como desenvolvedores?
Ou talvez o teste de unidade simplesmente produza o maior ganho comparado à complexidade de automatizá-lo?
O que você tem com testes de unidade automatizados, testes de integração automatizados e testes de aceitação automatizados? Na sua experiência, o que gerou o maior ROI? e porque?
Se você tivesse que escolher apenas uma forma de teste para ser automatizada em seu próximo projeto, qual seria?
Desde já, obrigado.
fonte
Respostas:
Um fator importante que torna os testes de unidade extremamente úteis é o feedback rápido .
Considere o que acontece quando você tem seu aplicativo totalmente coberto com testes de integração / sistema / funcional (que já é uma situação ideal, longe da realidade na maioria das lojas de desenvolvimento). Geralmente, eles são executados por uma equipe de testes dedicada.
Isso tudo pode levar dias ou até semanas. A essa altura, você já estava trabalhando em outras tarefas, para não ter os mínimos detalhes do código escritos anteriormente. Além disso, você normalmente não tem nenhuma prova direta de onde realmente está o erro, portanto, leva um tempo considerável para encontrar e corrigir o erro.
Considerando que no teste de unidade (TDD)
Tudo isso acontece em questão de minutos .
Isso não quer dizer que testes de integração / sistema não sejam úteis; eles apenas servem a propósitos diferentes. Com testes de unidade bem escritos, você pode capturar uma grande proporção dos erros no código antes que eles cheguem à fase de integração, onde já é consideravelmente mais caro encontrá-los e corrigi-los. Você está certo de que os testes de integração são necessários para detectar os tipos de bugs difíceis ou impossíveis de serem detectados nos testes de unidade. No entanto, na minha experiência, esses são os mais raros; a maioria dos erros que eu vi são causados por alguma omissão simples ou até trivial em algum lugar dentro de um método.
Sem mencionar que o teste de unidade também testa suas interfaces quanto à usabilidade / segurança, etc., fornecendo um feedback de vital importância para melhorar seu design e APIs. Qual IMHO pode reduzir consideravelmente as chances de erros de integração de módulos / sistemas: quanto mais fácil e limpa uma API for, menor a chance de mal-entendidos ou omissões.
O ROI depende de muitos fatores, provavelmente o principal deles é se o seu projeto é greenfield ou legado. Com o desenvolvimento greenfield, meu conselho (e experiência até agora) é fazer testes de unidade no estilo TDD desde o início. Estou confiante de que este é o método mais econômico neste caso.
Em um projeto legado, no entanto, construir uma cobertura suficiente de testes de unidade é uma tarefa enorme , que será muito lenta para gerar benefícios. É mais eficiente tentar cobrir a funcionalidade mais importante com testes de sistema / funcionais via interface do usuário, se possível. (pode ser difícil testar aplicativos GUI de desktop automaticamente através da GUI, embora as ferramentas de suporte a testes automatizados estejam melhorando gradualmente ...). Isso fornece uma rede de segurança grossa, porém eficaz, rapidamente. Em seguida, você pode começar a criar gradualmente testes de unidade nas partes mais críticas do aplicativo.
Essa é uma questão teórica e acho inútil. Todos os tipos de testes têm seu uso na caixa de ferramentas de um bom engenheiro de SW, e todos eles têm cenários em que são insubstituíveis.
fonte
Todos os tipos de teste são muito importantes e garantem que diferentes aspectos do sistema estejam nas especificações. Então, trabalhando de trás para frente, "Se eu tivesse que escolher um tipo de teste ..." eu não escolheria. O teste de unidade fornece um feedback diferente do teste de integração ou teste interativo de uma pessoa.
Aqui está o tipo / benefício dos testes que fazemos:
Teste opcional, mas recomendado:
Para entender por que o teste de unidade tem uma vantagem sobre o teste de integração, é necessário entender as ordens de magnitude de testes adicionais que você precisa para ser abrangente. Para todos os resultados possíveis para a unidade A, é necessário um teste. O mesmo para a unidade B. Agora, se os dois trabalharem juntos para uma solução mais completa, o número de testes será combinatório. Em resumo, para testar todas as permutações de interação entre a unidade A e a unidade B, você precisa de testes A * B. Adicione a unidade C e o número de testes para o trio seria A * B * C.
É aqui que o conceito de interfaces e limites de objetos se torna muito importante. As interfaces representam um determinado contrato. Um implementador de uma interface concorda que ele se comportará de uma certa maneira. Da mesma forma, um consumidor de uma interface concorda que usará a implementação de uma certa maneira. Ao escrever um teste que coleta todas as classes que implementam uma interface, você pode facilmente testar se cada implementação observa os contratos de interface. Isso é metade da equação. A outra metade é testar o lado do consumidor - que é onde os objetos simulados entram para brincar. A simulação é configurada para garantir que as interações estejam sempre nas especificações. Neste ponto, basta alguns testes de integração para garantir que os contratos de implementador / consumidor estejam corretos.
fonte
Estas são ferramentas diferentes com objetivos diferentes:
O teste de unidade é uma ferramenta de design (TDD) e é quase um pré-requisito para refatoração.
Os testes de integração são ótimos para visualizar o andamento do projeto e também ótimos para evitar erros de regressão.
O ponto a lembrar é que você não pode realmente projetar com testes de integração e não encontrará regressões com testes de unidade.
fonte
Eu usei o Selenium extensivamente para verificações de sanidade.
Em uma grande empresa de publicação na web, quando uma nova versão era feita, normalmente eram necessários cerca de 3 testadores em torno de uma hora ou duas para visitar todas as famílias de sites e garantir que tudo estivesse correto, de acordo com o script de teste. Com o Selenium, conseguimos automatizar o teste e distribuí-lo em várias máquinas e navegadores. Atualmente, quando os scripts de teste são executados, leva 3 PCs cerca de 10 minutos para fazer automaticamente a mesma coisa E emitir um relatório bonito.
O melhor do selênio é que você pode associá-lo a estruturas de teste de unidade como XUnit, TestNG ou MSTest.
Na minha experiência, foi extremamente valioso; no entanto, a configuração de algo assim realmente depende do seu projeto e da sua equipe, portanto o ROI definitivamente varia.
fonte
O melhor ROI é geralmente o teste mais antigo que pode encontrar esse tipo de bug.
O teste de unidade deve encontrar a maioria dos bugs que estão apenas em um método ou talvez em um componente. Ele encontra bugs que geralmente podem ser corrigidos em minutos, com tempos de entrega totais inferiores a uma hora. Testes MUITO baratos, erros MUITO baratos para encontrar e corrigir! Se esses erros foram incluídos nos testes de integração, a recuperação poderia ser mais parecida com um dia (as execuções de testes geralmente acontecem todas as noites), supondo que o erro não seja ocluído por outro erro; além disso, provavelmente haverá mais bugs introduzidos, já que outro código foi gravado no código inicial de buggy; além disso, qualquer reprojeto afetará mais partes do código. Além disso, deixar passar mais bugs significa ter que fazer muito mais execuções de teste antes que o teste de integração possa ser concluído. Testes de unidade ruins geralmente estão no centro de tarefas longas, onerosas e carasciclos de integração de teste. Ignorar o teste de unidade pode reduzir pela metade o tempo de desenvolvimento, mas o teste levará de três a quatro vezes, pelo menos, o projeto inteiro terá o dobro de duração e você ainda terá uma qualidade mais baixa do que se tivesse testado o IME por unidade.
O teste de integração geralmente é o teste real mais antigo que pode encontrar erros de integração (embora os processos de revisão possam encontrar alguns erros antes da gravação do software ou antes do teste do código). Você deseja encontrar esses bugs antes de começar a mostrar o software para o usuário ou a versão, pois a correção de bugs no último momento (ou a correção a quente!) É muito cara. Você não pode encontrar esses erros mais cedo, quando eles seriam mais baratos de corrigir, porque você precisa de vários componentes de trabalho para integrar (por definição). O teste de integração fica mais lento quando erros que não têm nada a ver com partes em interação (como pequenos erros de digitação) precisam ser resolvidos primeiro antes que os testes mais interessantes possam começar.
O teste de aceitação do usuário está garantindo que o software faça o que o cliente deseja (embora, esperançosamente, o cliente esteja envolvido o tempo todo, para reduzir o risco de encontrar uma enorme lacuna entre as expectativas e o software real no final do projeto - MUITO caro !). No momento em que você chega a esse estágio de teste, você realmente deve acreditar que a maioria dos bugs do seu produto, em comparação com as especificações, pelo menos, já foram encontrados. O teste de aceitação do usuário tem mais a ver com garantir que o produto atenda às necessidades do cliente do que garantir que não haja erros em comparação com as especificações.
Se eu fosse automatizar apenas um tipo de teste, seria o teste de unidade. Os testes de integração podem ser feitos manualmente e foram feitos dessa maneira por muitas empresas importantes por anos. É mais demorado realizar manualmente o trabalho que pode ser feito por um computador repetidamente, e muito mais caro para a maioria dos projetos, sem mencionar chato e propenso a erros, mas pode ser feito. Os testes de aceitação do usuário geralmente são manuais, pois os usuários geralmente não sabem como automatizar seus testes enquanto ainda testam com o que se importam. Os testes de unidade DEVEM ser automatizados. Você precisa poder executar todos os testes de unidade em alguns segundos, sob demanda, com a frequência de poucos minutos. Os seres humanos simplesmente não conseguem nem chegar perto com testes manuais. Sem mencionar que os testes de unidade estão no código e não podem ser executados sem chamá-los através do código, ou seja, automatizando-os.
Uma coisa a ter em mente é que este é um fórum principalmente para desenvolvedores, não para testadores. O teste de integração é implementado principalmente pelos testadores. O teste de unidade é implementado pelos desenvolvedores. Naturalmente, os desenvolvedores falam mais sobre testes de unidade do que outros tipos de testes. Isso não significa que eles não acham que outros testes sejam importantes. Significa apenas que eles realmente não fazem isso (ou fazem isso com menos frequência).
fonte
Eu sinto que os testes de aceitação são o rei neste cenário.
Se um commit interrompe os testes de aceitação, ele precisa ser resolvido.
Os testes de aceitação informam onde está o seu software, os testes de unidade não.
Portanto, os testes de unidade podem fornecer uma falsa sensação de segurança.
fonte
A questão não é tanto o que é mais importante, como o que pode ser automatizado e executado rapidamente.
Os testes de unidade mostram se um componente pequeno é adequado para o propósito de uma maneira específica e geralmente são pequenos e rápidos de executar. Por serem pequenas, geralmente são razoavelmente fáceis de automatizar.
Testes de integração mostram se os componentes funcionam juntos. Eles geralmente são muito maiores e podem não ser fáceis de automatizar. Eles podem demorar mais para serem executados. Existe um valor em poder executá-los automaticamente, mas é uma tarefa maior e eles não serão executados com a mesma frequência.
Testes de aceitação mostram se um projeto é aceitável ou não. Normalmente, é impossível automatizar completamente (embora os testes automatizados possam desempenhar um papel), pois normalmente é impossível definir os requisitos exatos e completos em uma questão formal menos complicada do que o próprio código-fonte. O teste de aceitação geralmente inclui usuários em potencial fazendo as coisas com o sistema e observando que os resultados são satisfatórios em todos os aspectos, o que normalmente é parcialmente subjetivo. Como o teste de aceitação geralmente é executado uma vez (clientes diferentes normalmente desejam fazer seus próprios testes de aceitação separados), não vale a pena automatizar.
fonte