Teste de unidade automatizado, teste de integração ou teste de aceitação [fechado]

29

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.

Bjarke Freund-Hansen
fonte
Gostaria apenas de adicionar um link tardio aos testes de integração do JB Rainsberger Are A Scam . Ele destaca muitas das razões pelas quais os testes de integração são uma economia falsa.
Tim
6
Este é mais um exemplo de fechamento de uma pergunta que estava perfeitamente bem neste site quando foi feita há três anos! É realmente irritante contribuir para uma comunidade onde as regras mudam e você simplesmente joga fora todas as coisas antigas!
Bjarke Freund-Hansen

Respostas:

34

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.

  • Você confirma uma alteração no repositório SCM,
  • algum tempo (possivelmente dias) depois, os testadores recebem um novo release interno e começam a testá-lo,
  • eles encontram um erro e enviam um relatório de erro,
  • (no caso ideal) alguém atribui o relatório de erro a você.

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)

  • você escreve um teste,
  • você escreve algum código para satisfazer o teste,
  • o teste ainda falha,
  • você olha o código e normalmente tem uma experiência de "oops" em alguns segundos (como "oops, esqueci de verificar essa condição!") e, em seguida,
  • corrija o erro imediatamente.

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 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?

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.

Se você tivesse que escolher apenas uma forma de teste para automatizar em seu próximo projeto, qual seria?

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.

Péter Török
fonte
2
+1 para "feedback rápido" para testes de unidade. Além disso, é muito útil para executar como pós-confirmação em um servidor de Integração Contínua.
precisa saber é o seguinte
1
"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." - Gostaria de poder votar várias vezes apenas por isso! Pessoas que pensam que podem encontrar uma ferramenta / método de teste ideal e aplicá-la em todos os lugares estão me desgastando.
Ptyx
8

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 de unidade - garante que as unidades estejam executando o trabalho como esperamos. Testamos contratos de fornecedor e consumidor para todas as interfaces - e isso é bastante fácil de automatizar. Também verificamos nossas condições de contorno, etc.
  • Teste de integração - garante que as unidades estejam trabalhando juntas em conjunto. Isto é principalmente para testar nosso design. Se algo quebrar aqui, precisamos ajustar nossos testes de unidade para garantir que não ocorra novamente.
  • Teste do sistema - garante que o sistema atenda aos requisitos / especificações. Normalmente, as pessoas fazem esse tipo de teste.
  • Teste de aceitação - o cliente faz isso para verificar se o produto final faz o que é anunciado.

Teste opcional, mas recomendado:

  • Teste da experiência do usuário: Embora recebamos um feedback decente dos testes do sistema, fazer com que as pessoas do cliente visualizem determinados pré-lançamentos pode realmente ajudar a determinar se precisamos mudar as coisas antes que seja tarde demais.

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.

Berin Loritsch
fonte
"Teste do sistema - garante que o sistema atenda aos requisitos / especificações. Geralmente, as pessoas fazem esse tipo de teste". Testes de integração de sistema / aka funcional / aka "ponta a ponta" / aka de alto nível também são bons para automação.
MiFreidgeim pare de ser mau
3

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.

Javier
fonte
@ você não pode realmente projetar com testes de integração e não encontrará regressões com testes de unidade. Exatamente!
Chankey Pathak
Os testes de unidade podem encontrar regressões causadas pela refatoração, por exemplo, um método auxiliar compartilhado alterado. Os testes de integração são muito melhores para isso.
StuperUser
O segundo ponto sobre testes de integração inclui testes de "sistema / funcional" (também conhecido como "de ponta a ponta")
MiFreidgeim deixa de ser mau
Totalmente acordado; um argumento semelhante foi apresentado alguns anos atrás por Steve Sanderson. Veja a tabela "Objetivo - Técnica mais forte" em sua postagem no blog de 2009 em blog.stevensanderson.com/2009/08/24/… para pensamentos um tanto complementares aos seus aqui.
Mark A. Fitzgerald
1

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.

Ryan Hayes
fonte
1

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).

Ethel Evans
fonte
Obrigado especialmente por esse último parágrafo, não pensei nisso.
Bjarke Freund-Hansen
Para sua informação, atualizei a resposta desde que você a leu - percebi que não li a pergunta original com atenção suficiente
Ethel Evans
@EthelEvans, seus motivos sobre as prioridades dos testes de unidade estão corretos para novos projetos. Para projetos legados, que foram escritos sem a automação da cobertura de teste, os testes de integração de sistema / aka funcional / aka de alto nível são os mais importantes. Veja a última parte da resposta programmers.stackexchange.com/a/39370/31574 .
MiFreidgeim pare de ser mau
@ MichaelFreidgeim, em última análise, depende de quão estáveis ​​são as interfaces. A automação de testes de alto nível pode incorrer rapidamente em custos proibitivos de manutenção, se ficarem desatualizados rapidamente. Nesse caso, automatize mais baixo para ajudar a criar estabilidade e use testes exploratórios (possivelmente baseados em sessões ou listas de verificação) para E2E e testes de integração para evitar incorrer em custos de manutenção de automação desagradáveis. Porém, nem todos os projetos herdados têm interfaces estáveis ​​- especialmente se estiverem sendo refatorados ou re-arquitetados de forma agressiva.
Ethel Evans
1

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.

godelfiend
fonte
0

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.

David Thornley
fonte