Por que os testes automatizados continuam falhando na minha empresa?


178

Tentamos introduzir testes automatizados para desenvolvedores várias vezes na minha empresa. Nossa equipe de controle de qualidade usa o Selenium para automatizar testes de interface do usuário, mas eu sempre quis apresentar testes de unidade e testes de integração. No passado, cada vez que tentávamos, todo mundo ficava empolgado pelo primeiro ou dois meses. Então, vários meses depois, as pessoas simplesmente param de fazer isso.

Algumas observações e perguntas:

  1. O teste automatizado realmente funciona? A maioria dos meus colegas que trabalhavam em outras empresas tentou e falhou ao implementar uma estratégia de teste automatizada. Eu ainda não vi uma empresa de software da vida real que realmente o usa e não fala apenas sobre isso. Muitos desenvolvedores veem os testes automatizados como algo ótimo em teoria, mas que não funciona na realidade. Nossa equipe de negócios adoraria que os desenvolvedores fizessem isso mesmo a um custo de 30% de tempo extra (pelo menos assim o dizem). Mas os desenvolvedores são céticos.

  2. Ninguém realmente sabe como fazer testes automatizados corretamente. Sim, todos nós lemos os exemplos de testes de unidade na internet, mas usá-los para um grande projeto é algo completamente diferente. O principal culpado é zombar / stubbing do banco de dados ou qualquer outra coisa que não seja trivial. Você acaba gastando mais tempo zombando do que escrevendo testes reais. Então, quando começa a demorar mais tempo para escrever testes do que o código, é quando você desiste.

  3. Existem bons exemplos de testes de unidade / testes de integração de sistemas usados ​​em aplicativos da Web complexos e centrados em dados? Algum projeto de código aberto? Nossa aplicação é centrada em dados, mas também possui muita lógica de domínio. Eu tentei a abordagem de repositório em algum momento e achei muito bom para testes de unidade, mas teve o preço de otimizar o acesso a dados facilmente e adicionou outra camada de complexidade.

Temos um grande projeto realizado por 20 desenvolvedores experientes. Este parece ser o ambiente ideal para introduzir testes de unidade / testes de integração.

Por que isso não funciona para nós? Como você fez isso funcionar na sua empresa?


14
Qual é a sua pilha de tecnologia?
Florian Margaine

7
Os WebForms são quase impossíveis de realizar o teste de unidade corretamente. Você pode usar um padrão MVP (Model / View / Presenter) para mover a lógica da apresentação para um componente testável.
Pete

12
@MasonWheeler: Nos dois casos, você construiu um argumento fantástico que nega premissas que não foram aceitas em primeiro lugar: ou seja, que existem testes de unidade para provar a exatidão.
Steven Evers

10
@ MasonWheeler- Usando esse argumento, você nunca deve tentar qualquer controle de qualidade, porque nunca provará que não há bugs. Esse nem é o objetivo. Uma boa estratégia automatizada de interface do usuário e testes de unidade é apenas liberar o controle de qualidade dos testes rotativos e permitir que eles se concentrem nos testes exploratórios.
21413 Alex

15
Estou chocado que várias pessoas declararam que nunca haviam visto testes automatizados por mais de alguns meses. Eu trabalhei para cerca de cinco grandes empresas na Alemanha como consultor e elas o demitiriam se você não fizesse testes. O teste automatizado não é um assunto teórico, é praticado com sucesso em todo o mundo e aumenta significativamente a qualidade do código (se bem feito).

Respostas:


89

A parte mais difícil de fazer o teste de unidade é conseguir a disciplina para escrever testes primeiro / mais cedo. A maioria dos desenvolvedores está acostumada a apenas mergulhar no código. Também atrasa o processo de desenvolvimento desde o início, enquanto você tenta descobrir como escrever um teste para o código. No entanto, à medida que você melhora nos testes, isso acelera. E por causa dos testes de escrita, a qualidade inicial do código começa mais alto.

Ao iniciar, tente apenas escrever testes. Não se preocupe tanto com zombarias / stubbing no começo. Mantenha os testes simples. Os testes são de código e podem / devem ser refatorados. Embora nesse sentido, se algo for difícil de testar, também possa ser o design. O TDD se esforça para usar a maioria dos padrões de design (na minha experiência, particularmente o padrão de fábrica).

Certifique-se de que os testes obtenham um nível de visibilidade. Integre-os no processo de lançamento, durante a revisão do código, pergunte sobre eles. Qualquer erro encontrado deve ser testado. É nessas coisas que o TDD brilha.

Aqui estão alguns recursos que eu achei úteis:

http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

http://www.agitar.com/downloads/TheWayOfTestivus.pdf

Editar:

Uma coisa a ter em mente quando você está escrevendo testes. Você não está tentando especificar nada sobre a implementação do código, apenas o comportamento. Quando você escreve código, você o testa o tempo todo. Tentando executá-lo com instruções de depuração e assim por diante. Escrever testes formaliza isso e fornece um registro dos testes que você possui. Dessa forma, você pode verificar sua funcionalidade com confiança, sem ignorar acidentalmente um caso de teste que você lembrou no meio do processo de desenvolvimento.


Outra maneira de abordar a introdução disso como um recurso de diagnóstico ... também conhecido como POST (power on self test), que pode quase fornecer o código do cliente ... e não apenas um monte de testes simples, que devem ser os testes e as funções.
23613 JustinC

Além disso, evite os anti-padrões TDD .
Gary Rowe

4
Misko Hevery também tem alguns ótimos vídeos no youtube sobre como escrever código testável que eu achei inestimável. youtube.com/watch?v=acjvKJiOvXw
Despertar

"Certifique-se de que os testes tenham um nível de visibilidade" - isso é fundamental para o sucesso. Se ninguém puder ver o desempenho de seus testes, eles não verão o valor. Os testes devem ser executados no check-in automaticamente como parte de uma integração contínua e depois relatados. Eu trabalho na Tesults ( tesults.com ) e a razão de existir é devido ao enorme impacto que a visibilidade do teste proporciona.
Skill M2

77

De muitas maneiras, eu concordo com sua equipe.

  1. A maioria dos testes de unidade é questionável em valor. Como a grande maioria dos testes parece ser muito simples.

  2. É muito mais difícil escrever um bom código testável do que apenas trabalhar código. Há uma grande porcentagem da comunidade de desenvolvedores que acredita em fazê-lo funcionar, em comparação com a qualidade do código / design em si. E uma porcentagem ainda maior que nem sabe o que é um código de qualidade.

  3. Pode levar muito mais tempo para escrever o código do teste de unidade do que o próprio código.

  4. Descobrir como testar adequadamente o código mais complicado (isto é, o que você realmente está interessado em testar minuciosamente) está além dos recursos de muitos desenvolvedores.

  5. A manutenção de testes de unidade leva muito tempo. Pequenas alterações podem ter grandes efeitos de ondulação. O principal objetivo dos testes de unidade automatizados é descobrir se as alterações quebraram o código. No entanto, 99% das vezes o que acaba quebrando são os testes e não o código.

Com todos os problemas acima, ainda não há uma maneira melhor de fazer alterações no código e ter algum nível de confiança de que algo não ocorreu inesperadamente do que automatizar seus testes.

Alguns dos itens acima podem ser aliviados até certo ponto, não seguindo o livro de testes de unidade.

Muitos tipos de projetos / aplicativos são melhor testados automatizando testes no nível do módulo / pacote. Na minha experiência, a maioria dos erros de codificação não ocorre porque o código de uma classe foi codificado incorretamente, mas porque o codificador não entendeu como sua classe deveria funcionar com outras classes. Eu já vi muito estrondo neste tipo de teste. Mais uma vez, porém, esses testes são mais difíceis de escrever do que os testes de unidade (nível de classe).

Realmente se resume a se os desenvolvedores acreditam no processo ou não. Se o fizerem, eles escreverão bons testes de unidade, encontrarão os erros mais cedo e serão proponentes. Se não o fizerem, seus testes de unidade serão, em geral, inúteis e não encontrarão nenhum erro, e sua teoria de testes de unidade como inútil será comprovadamente verdadeira (em suas mentes).

O ponto principal é que eu nunca vi a abordagem de teste de unidade automatizada completa funcionar por mais de um par de meses, mas a idéia de testes de unidade automatizados ainda persiste, apesar de sermos seletivos no que realmente precisa de teste. Essa abordagem tende a ter muito menos críticas e é mais aceita por todos os desenvolvedores do que apenas alguns.


24
Eu tendem a concordar com isso. Adquirimos o hábito de fazer testes somente depois que algo quebra (mesmo que essa interrupção tenha ocorrido durante o desenvolvimento). Nunca na frente, leva muito tempo para receber pouca recompensa.
Izkata

5
@ Izkata, a outra abordagem que eu já fiz com sucesso é escrever um número relativamente pequeno de testes de alto nível chamando o Frobinate()método de nível superior (em vez das dezenas de métodos menores chamados abaixo) depois que o sistema foi verificado por outros meios para servir como teste de fumaça, que nenhuma das mudanças de nível inferior quebrou nada. Geralmente esses testes usavam os mesmos dados que faziam parte da libra nos testes do usuário do teclado, fornecidos para que o cliente possa ver que o sistema está fazendo o que deseja. Posteriormente, as ferramentas de cobertura de código podem identificar onde casos extremos ainda não estão sendo cobertos.
Dan Neely

3
Eu não disse "teste automatizado completo", eu disse "teste UNIT automático completo". Grande diferença. Eu tenho usado testes automatizados no nível do módulo há pelo menos uma década. O teste de unidade é no nível da classe. Acredito que ganho mais dinheiro ao testar aulas que deveriam trabalhar juntas, e não como indivíduos. No entanto, mesmo lá, ainda usamos uma abordagem pragmática e escolhemos seletivamente o que / onde escrever testes automatizados.
Dunk

2
Sem uma boa cobertura de teste de unidade, como você refatorar? Ou, sem refatorar, como você evita que o código degenere gradualmente para a impossibilidade de manutenção?
Kevin cline #

1
@ Leonardo Eles não fizeram - eles estavam com muito medo de mudar alguma coisa. Ou eles economizaram toda essa dívida técnica e reservaram algumas semanas / meses depois para resolvê-la de uma só vez.
GraemeF

33

O principal culpado é zombar / stubbing do banco de dados ou qualquer coisa não simples.

E aí está o seu problema.

Todo mundo faz boas observações sobre como integrar o teste de unidade ao seu ambiente. Como forçar as pessoas a fazê-lo o suficiente para que vejam o valor prático e ele "adira". Mas se é super doloroso de fazer e / ou não oferece nenhum benefício, ele não ficará.

A remoção de um banco de dados deve ser simples. Em vez de sua interface recorrer a algum suporte de banco de dados para fornecer seus resultados, você coloca um objeto codificado simples. Se você não pode fazer isso, seu design / arquitetura tem problemas. Seu código assume que está indo para um banco de dados ou você não tem a abstração da interface para variar.

Isso não é apenas uma preocupação de teste / qualidade. Assim que você deseja alterar os provedores de banco de dados, ou ir para a nuvem, ou oferecer suporte a aplicativos móveis não conectados, seu design simplesmente falha. Se você não pode suportar os casos mais simples de flexibilidade, certamente não pode suportar as coisas mais complexas que sua empresa inevitavelmente exigirá.


4
A codificação do banco de dados retorna valores de um pequeno esboço de um objeto simulado é uma boa maneira de isolar o teste de qualquer coisa no banco de dados que possa alterar e quebrar o código (por exemplo, renomeação de colunas). É apropriado em determinadas circunstâncias, mas é importante manter um banco de dados de teste temporário fácil de usar, a menos que você queira que as coisas quebre algum dia quando você o alterar. Se o seu código quebrar quando você trocar o banco de dados, isso é uma falha do código que o teste deve estar pegando (e se você quiser evitar isso, você deverá executar o conjunto de testes em vários bancos de dados.)

8
@fennec - testes de unidade não existem para testar o banco de dados, eles estão lá para testar o código que depende dos valores do banco de dados para funcionar.
Telastyn

3
Tudo bem até que você esteja testando o código que manipula o banco de dados. : P que, para muitas pessoas, é muito do código deles.

4
@fennec - É um pouco mais complexo do que simples simplificar a interface para garantir que suas gravações estejam gravando o objeto certo. Isso fica difícil quando suas classes estão tentando enviar o SQL diretamente para a sua interface (leia: você tem um design horrível).
Telastyn

5
@Telastyn talvez eu esteja entendendo mal, mas eventualmente algumas classes precisam ficar sujas e escrever o SQL ou gravar o arquivo ou enviar os dados ou a interface com a GPU. A maioria das abstrações tem vazamentos inevitáveis ​​em algum nível; eles são simplesmente pragmáticos e não necessariamente horríveis.
Fila de aprendizes

21

Você precisa começar com algo pequeno, simples de automatizar e de alto valor. Puxe algumas frutas doces e baixas, e você poderá vender o processo. Mostre como ele salvou alguém tarde da noite ou uma ligação de fim de semana. Então você pode expandir a partir daí.

Para executar bem os testes automatizados, você precisa de alguém que seja um recurso e um evangelista, e que tenha participado de gerências de nível superior.

Trate seu desenvolvimento automatizado de testes como qualquer outro projeto ágil. Produza testes concluídos regularmente.

Adicionando do comentário: Esse é mais um problema de gerenciamento. O código é considerado "concluído" antes de ser documentado? Antes de fazer o check-in? Antes de incluir e passar nos testes de unidade?

Como você aborda isso realmente depende do seu papel. Você é um colega? Nesse caso, mostre aos outros como isso facilita seu código para reutilizar e manter. Você é um líder? Escolha seu programador que tem mais problemas de código e ajude-o a adicionar testes para evitar esses problemas. Você é um chefe? Defina como padrão que "o código não é feito até que os testes de unidade estejam chegando e passando.


17
"Puxe algumas frutas doces e baixas, e você poderá vender o processo.": Eu acho que elas já chegaram a esse estágio (elas viram vantagens potenciais no uso de testes de unidade) e é por isso que elas foram convencidas a dar uma tentativa. O problema é, em vez disso, como escalar os frutos baixos para testes de unidade sistematicamente. O único projeto em que trabalhei no qual os testes de unidade foram utilizados sistematicamente tinha mais código de teste de unidade do que o código real do produto. Se uma equipe não estiver preparada para gastar mais tempo codificando testes de unidade do que o código real do aplicativo, a abordagem da IMO provavelmente não funcionará.
Giorgio

4
Isso é mais um problema de gerenciamento. O código é considerado "concluído" antes de ser documentado? Antes de fazer o check-in? Antes de incluir e passar nos testes de unidade? Como você aborda isso realmente depende do seu papel. Você é um colega? Nesse caso, mostre aos outros como isso facilita seu código para reutilizar e manter. Você é um líder? Escolha seu programador que tem mais problemas de código e ajude-o a adicionar testes para evitar esses problemas. Você é um chefe? Defina como padrão que "o código não é feito até que os testes de unidade cheguem e passem."
Skip Huffman

1
@SkipHuffman, seu comentário deve ser adicionado como uma edição da resposta atual.
Radu florescu

15

Siga estas regras básicas. Testes:

  1. deve executar regularmente! Você pode executar testes em todas as versões, antes / depois de cada check-in ou apenas todas as manhãs. O acionamento automático é altamente preferível ao acionado manualmente. Porque, embora em teoria você possa ser responsável por garantir que todos executem testes, se não for automatizado, provavelmente não acontecerá com bastante frequência! E se você não executar seus testes com frequência suficiente, os dois encontrarão os erros tarde demais, incentivando muitos testes interrompidos, o que leva ao ponto 2:

  2. Você ainda terá sucesso se esses testes, agora em execução regularmente, não atrapalharem . Com o que entendemos testes:

    uma. não deve demorar muito para ser executado (subjetivamente) pelo valor que eles fornecem! Faça seus testes muito rápido. Não permita que as pessoas façam check-in em testes que serão uma perda de tempo para deixá-los executar!

    b. não deve ser confiável. Evite testes multithread, se possível. Aplique práticas de engenharia aos seus testes, assim como seu outro código: particularmente - revise o código dos seus testes!

    c. não deve ser mais difícil de corrigir e manter do que o código real testado. Sua velocidade de codificação realmente será péssima se uma linha minúscula mudar para sua base de código exigir que você faça 10 testes diferentes.

E finalmente, regra número 3. Os testes não devem apenas falhar em fornecer valor negativo, como na regra 2, eles devem fornecer valor positivo. Testes ...

  1. deve realmente estar dizendo algo sobre o qual você se importa quando eles falham! (Não há testes com mensagens de erro obscuras ou apenas com queixas ridículas como 'você esqueceu de executar o teste em uma máquina Windows 2008', por favor!).

Uma maneira popular de violar a regra 3 é testar a coisa errada . Às vezes, isso ocorre porque um teste é muito grande ou muito fora de foco. Mas, geralmente, resulta de não testar algo com o qual o cliente se preocupa e testar detalhes irrelevantes da implementação. (Mas, às vezes, testar os detalhes da implementação também faz um teste eficiente - na IMO, é necessário praticar o processo de decidir qual.)

Conclusão: essas regras básicas apontam você na direção geral de uma disciplina de teste sustentável , que é o que você deseja desesperadamente. Ao testar, pergunte a si mesmo se esse teste é realmente sustentável e sustentável. Lembrar:

  • se os testes não são sustentáveis, caem em desuso e, assim, tornam-se um desperdício de esforço
  • se os testes não são sustentáveis, você para de fazer testes e sua equipe para de melhorar! E, ponto final:

Testar é realmente difícil. Você deve esperar que os testes de sua equipe sejam basicamente ruins quando você começar a escrever testes . Não desanime. Não jogue fora os testes antigos, sempre que notar que sugam e são insustentáveis.


12

1. Isso realmente funciona?

Sim, sim - se feito corretamente. O ponto é que os testadores precisam ajustar e estender seus scripts automatizados depois que os engenheiros implementam novos recursos.

2. Ninguém é realmente experiente ou sabe como fazer testes automatizados corretamente.

Procure um consultor (alguém que saiba como é feito corretamente). Ou invista mais tempo. A alternativa é ter uma equipe de teste maior, que faça o mesmo teste manualmente (o que é propenso a erros).

3.Temos um grande projeto com 20 desenvolvedores experientes trabalhando nele. Portanto, deve ser um ótimo ambiente para introduzir testes de unidade / testes de integração. Por que isso não funciona para nós? Como você fez isso funcionar na sua empresa?

Eu não os chamaria de "bons desenvolvedores experientes" se eles se recusassem a fazer testes de unidade. Existem muitos artigos excelentes sobre os benefícios positivos dos testes (testes de unidade e integração) e, no final, tudo se resume a quanto um bug custa à sua empresa . Por exemplo, trabalho em uma empresa onde a qualidade importa, portanto, os testes de unidade e integração são inevitáveis. Você pode encontrar facilmente muitos artigos, informando que apenas os testes de unidade estão reduzindo o número de bugs em 30%! (Na verdade, está na faixa de 20 a 90%, em média 30%, mas ainda é muito.)

Para fazê-lo funcionar em sua empresa, contrate um consultor ou atribua essa tarefa a um engenheiro sênior (levará um tempo para fazê-lo). E então, force todos a seguir as regras.


20
Devo salientar que praticamente TUDO funciona "Se feito corretamente". No entanto, isso não é muito útil para todos, exceto para uma minoria minúscula de qualquer população. Para que um processo possa realmente afirmar que funciona, ele também deve funcionar quando concluído "mais ou menos".
Húmido

11
Vou salientar que a generalização excessiva da situação de todos para a sua própria (ou seja, eu não os chamaria de "bons desenvolvedores experientes" .. qualidade importa) não apenas demonstra sua falta de amplitude de experiência, mas não é muito produtiva. Toda indústria tem sua própria definição de "obras"; e que teste de graduação precisa ser feito nos níveis de unidade, integração e sistema. Muitos desenvolvedores "excepcionalmente bons" chegaram à conclusão de que os testes de unidade fornecem pouco retorno quando comparado aos testes de integração automatizados. Eles também percebem que isso provavelmente se aplica apenas a seu setor específico.
Húmido

11
"Eu não os chamaria de 'bons desenvolvedores experientes', se eles se recusarem a fazer testes de unidade". Esta é apenas a falácia do Não Verdadeiro Escocês. A indústria de software se deu bem por décadas sem testes de unidade e a maior parte dessa indústria continua se dando bem hoje. Pode ser uma boa ideia, mas simplesmente não é obrigatória.
Noah Yetter

1
"não perca tempo em testes de unidade": eu reformularia isso como "não perca tempo em testes de unidade inúteis". Testar cegamente tudo pode resultar em uma enorme perda de tempo.
Giorgio

1
@ Dunk Eu realmente odeio todo o fenômeno TDD do tipo teste primeiro, mas não posso concordar com a sua primeira declaração. Você está fazendo uma coisa certa ou não está. Você pode fazer um teste de unidade bem e talvez ver os méritos dele, mas nunca verá os méritos de qualquer coisa feita pela metade.
Erik Reppen

10

São muitas as razões pelas quais a introdução de testes automatizados pode falhar. Eu acho que tudo se resume ao fato de que os programadores tendem a não mudar seus hábitos de codificação e não são totalmente capazes de adotar testes de unidade.

Muitas pessoas que desejam iniciar o teste automatizado tentam apresentá-los a uma base de código existente. Eles tentarão escrever testes de integração que testam muitas funcionalidades do aplicativo existente ao mesmo tempo. Tais testes de integração são notoriamente muito difíceis e caros de manter. Conselho: introduza testes automatizados para uma nova base de código.

Testes de unidade são bons testes a serem automatizados. Tudo acima (testes de integração, testes de componentes, testes de sistema) também pode ser testado automaticamente, mas a relação custo-benefício diminui rapidamente, mais funcionalidades são testadas ao mesmo tempo. Esse efeito negativo é amplificado, se você criar esses testes com funcionalidades mal testadas por unidade. Conselho: introduza testes automatizados no nível de teste de unidade e crie testes de integração automatizados em uma base sólida de testes de unidade .

Dos pontos acima, grande parte do sucesso dos testes automatizados depende da eficácia dos testes unitários. Você tem testes de unidade eficazes se se sentir produtivo com testes de unidade. Quando as pessoas começam com o teste de unidade, elas tendem a adaptar seus códigos e hábitos de codificação existentes em testes de unidade. Ironicamente, essa é a maneira mais difícil de aprender testes de unidade. Além disso, o teste de unidade exige que você altere a maneira como codifica (por exemplo, aplicando os princípios do SOLID ). Muitos programadores logo param de escrever testes de unidade porque acham que a curva de aprendizado é muito íngreme e acham estranho envolver testes de unidade em torno de um código projetado não tão testável. Conselho: Aprenda o teste de unidade desde o início com o novo código e lide com o fato de que você precisa alterar seus hábitos de codificação.

Existem muitos outros fatores, mas eu achei que, para a maioria dos programadores, é problemático mudar sua maneira de codificar. Código escrito sem teste apenas parece diferente. Se você não conseguir compactar seu código em um design testável, provavelmente falhará ao escrever testes de unidade eficazes. Isso destrói o terreno para testes automatizados eficazes.

Eu experimentei isso sozinho e agora estou feliz em trabalhar em uma empresa que introduziu com sucesso testes automatizados. Eu poderia escrever muito mais sobre os outros fatores, mas acho que os hábitos de codificação e o teste de unidade são os mais importantes. Felizmente, existem outros que têm mais experiência do que eu e enchem os livros com seu conhecimento. Um desses livros é o Brownfield Application Development no .NET que eu realmente recomendo, pois você está usando a pilha de tecnologia da Microsoft.


Introduce automated tests on the unit test level and build automated integration tests on a solid foundation of unit tests.+1
c69 4/02/2013

10

Uma coisa que eu não vi claramente abordada nas respostas acima é que o teste de unidade é essencialmente um bem público e um custo privado. Eu escrevi um post sobre isso aqui .

O que se resume é que, embora um conjunto de testes beneficie a equipe ou um desenvolvedor individual, escrever o teste é um custo para quem o faz, na maioria das vezes.

Em resumo, a menos que a execução do teste seja aplicada de alguma forma - e as respostas acima listem várias maneiras diferentes de fazer isso - não há razão para um desenvolvedor individual fazer isso.

Em uma empresa em que trabalhei, escrever testes de unidade era uma parte necessária do fornecimento de um recurso. O novo código não era aceito, a menos que um teste de unidade fizesse parte do commit ou do novo recurso - houve breves revisões de código para cada "tarefa" que um desenvolvedor recebeu. Pode valer a pena implementar uma política semelhante no seu local de trabalho.


8

É interessante que o negócio seja mais pró-teste do que desenvolvedores! Parece-me que seu maior desafio será superar a resistência de seus desenvolvedores à mudança; eles precisam redefinir sua compreensão de seus trabalhos para incluir testes de unidade.

Nada pode ajudá-lo mais do que sucessos anteriores no teste de unidade para ajudar seus desenvolvedores a superar sua resistência ao escrever esses testes. Se você pressioná-los para fazer algo novo, certifique-se de pressionar primeiro por algo com uma recompensa quase garantida.

@SkipHuffman tocou nisso, mas vou dizer isso de uma vez. Algumas coisas são muito mais adequadas para testes automatizados do que outras. Para a primeira passagem, eu NÃO testaria o banco de dados ou a interface do usuário. A entrada de um banco de dados pode ser extremamente difícil de configurar e desmontar. Os testes de saída da interface do usuário tendem a ser rapidamente interrompidos pelas alterações de aparência que são completamente irrelevantes para seus testes.

O que eu chamaria de "middleware" é perfeito para testes de unidade. Código que definiu claramente as condições de entrada e saída. Se você seguir o princípio DRY (Não se repita), terá escrito algumas pequenas classes ou funções para resolver problemas recorrentes exclusivos do seu aplicativo.

O teste de unidade é uma ótima ferramenta para limitar o risco de alterar os componentes internos existentes. Escreva testes de unidade antes de alterar um componente interno que funcionou por um longo tempo. Esses testes provam que a funcionalidade atualmente em funcionamento é preservada. Quando você faz sua alteração e todos os testes de unidade são aprovados, você sabe que não quebrou nada "downstream". Se você encontrar um problema a jusante, adicione um teste de unidade para ele!

Ron Heifitz diria "resolver conflitos nos valores que as pessoas detêm, ou diminuir a diferença entre os valores que as pessoas defendem e a realidade que enfrentam. O trabalho adaptativo requer uma mudança de valores, crenças ou comportamento". Depois de superar a resistência humana à mudança, você pode se ramificar em áreas de teste mais difíceis, conforme apropriado.


6
"supere a resistência de seus desenvolvedores à mudança": nem toda resistência é sem uma razão e não se deve evitar uma discussão honesta usando o argumento "resistência à mudança".
Giorgio

7

Uma coisa sobre o teste automatizado é que ele exige que você escreva o código para poder ser testado. Isso não é algo ruim por si só (na verdade, é bom porque desencoraja muitas práticas que, em regra, devem ser evitadas), mas se você estiver tentando aplicar o teste de unidade ao código existente, é provável que não seja. foi escrito de forma testável.

Coisas como singletons, métodos estáticos, registros, localizadores de serviços etc. introduzem dependências que são muito difíceis de serem ridicularizadas. Violações da Lei de Demeter significam que muitas partes da sua base de código sabem muito sobre como outras partes da sua base de código funcionam, introduzindo outras dependências ocultas que podem ser difíceis de quebrar. Todas essas coisas dificultam o isolamento de um módulo do restante da base de código e, se você não pode testar seus módulos isoladamente, os testes de unidade perdem muito valor. Se um teste falha, é devido a uma falha na unidade em teste, ou devido a uma falha em uma de suas dependências, ou talvez seja porque os dados que estão sendo puxados por uma fonte de dados dependente não são o que o gravador de teste esperava. ? Se você puder'

A maioria das bases de código que vi que não foram criadas com o teste de unidade em mente tendem a ser intrinsecamente testáveis, pois os codificadores tendem a se concentrar em fazer o código funcionar da maneira que esperam, em vez de fazer o trabalho necessário para manter o acoplamento solto e as dependências explícitas . O código que foi escrito com o teste de unidade em mente tende a parecer muito diferente.

Muitas pessoas adotam uma abordagem ingênua ao teste de unidade quando começam a fazê-lo pela primeira vez; pensam que podem simplesmente escrever uma carga de testes para uma base de código existente e tudo será bom, mas nunca funciona dessa maneira por causa de as questões acima mencionadas. Eles começam a descobrir que precisam de quantidades excessivas de configurações em testes de unidade para executá-los, e os resultados geralmente são questionáveis ​​porque a falta de isolamento no código significa que você não pode rastrear o que causou uma falha no teste. Eles também tendem a começar a escrever testes "inteligentes" que demonstram algum aspecto altamente abstrato de como o sistema deve funcionar. Isso tende a falhar porque um teste de unidade "inteligente" é uma fonte potencial de bugs em si. O teste falhou devido a um erro no módulo testado, ou por causa de um bug no teste? Um teste deve ser tão torturante simples que obviamente não há possibilidade de um bug estar escondido nele. De fato, os melhores testes raramente têm mais de duas linhas, a primeira instruindo a unidade sob teste a fazer alguma coisa, a segunda afirmando que o que fez foi o que era esperado.

Se sua equipe leva a sério a adoção de testes de unidade, seria imprudente começar com um projeto existente. Os projetos existentes da sua equipe provavelmente não podem ser testados sem grandes refatorações. É melhor usar um novo projeto como base para aprender sobre testes de unidade, pois você tem uma lista limpa para trabalhar. Você pode projetar a nova base de código para favorecer a injeção de dependência em relação a singletons, registros e outras dependências ocultas. Você pode escrevê-lo para depender de interfaces, em vez de implementações e assim por diante. Você também pode (e deve) escrever os testes ao lado do código que está sendo testado, pois escrever os testes posteriormente resulta em testes de unidade que garantem que o módulo testado faça o que você pensa que deve ser feito, em vez daqueles que testam o que ele faz. o que as especificações dizem que deve fazer.

Depois de ganhar alguma confiança com o teste de unidade, sua equipe provavelmente começará a perceber as falhas no código existente que serão obstáculos aos testes de unidade. É quando você pode começar a trabalhar para refatorar o código existente para torná-lo mais testável. Não seja ambicioso e tente fazer isso tudo de uma só vez, ou tente substituir um sistema que funcione com um sistema totalmente novo, basta encontrar os bits da base de código que podem ser facilmente testados (os que não possuem quaisquer dependências ou onde as dependências sejam óbvias) e escreva testes para elas. Eu sei que disse que escrever um teste ao lado do código é preferível a escrever testes depois, mas mesmo um teste gravado posteriormente ainda tem valor como ponto de partida. Escreva os testes como se não soubesse nada sobre como a classe funciona, a não ser o que suas especificações dizem que deve fazer. Quando você executa os testes e obtém falhas, as especificações ou a implementação estão incorretas. Verifique duas vezes para determinar qual está errado e atualize o teste ou o código de acordo.

Depois de colher os frutos mais baixos, seu verdadeiro trabalho começa. Você precisa começar a encontrar as dependências ocultas na sua base de código e corrigi-las, uma de cada vez. Não fique ambicioso demais neste momento, continue fazendo um módulo de cada vez, ou mesmo apenas um problema em um módulo, até que os obstáculos aos testes sejam corrigidos e você possa passar para o próximo.

TL: DR: A maioria das pessoas acha que o teste é fácil e você pode adaptá-lo facilmente ao código existente. Ambas as suposições estão erradas. Se você embarcar em um projeto para realizar testes de unidade em seus projetos com esses dois fatos em mente, é mais provável que tenha sucesso.


dica: coloque o TL; DR: no topo - eu tive que ler todas as suas postagens apenas para chegar lá! (o que anula o meio ponto)
gbjbaanb

4
  • Existe alguém na sua empresa com vasta experiência em testes automatizados?

Caso contrário, as iniciativas de teste automatizadas provavelmente falharão. O teste automatizado é uma habilidade, como muitas outras habilidades em programação, e se você não tem ninguém com experiência em fazer isso, não é fácil saber se um teste automatizado é um bom teste automatizado com valor real ou ruim que será falha aleatoriamente / requer atualizações frequentes / não exerce nenhum código interessante.

  • Alguém tem poder de liderança? Eles são capazes de exigir mudanças?

Se ninguém escuta, não importa se eles dizem que o teste não é bom. (Observe que o poder de liderança não precisa ser formalizado. Ter uma equipe que se importa também é bom.)

  • Você está desenvolvendo ferramentas e processos para facilitar a implementação e a integração de testes automatizados no ciclo de desenvolvimento?

Os desenvolvedores são preguiçosos. Você precisa tornar as coisas que você deseja que sejam fáceis de realizar e as coisas que você não quer que sejam mais difíceis de realizar. Você deve certificar-se de que as bibliotecas de teste facilitem as tarefas associadas à configuração e desmontagem de testes, especialmente a configuração relacionada ao ambiente, como bancos de dados de teste ou similares. (A zombaria do banco de dados é discutida em alguns desses comentários, mas deve ser usada com cautela. Um banco de dados real deve ser fácil de rodar e permite testar a interação de componentes e ciclos de vida do processo, geralmente mais importantes e mais eficazes que o teste de unidade um acessador de dados individual.)

Você também deve garantir que seus IDEs tenham uma boa maneira de iniciar o conjunto de testes. Você deve executar o conjunto de testes com frequência para que as pessoas percebam quando ele falha, em vez de deixá-lo na miséria. Os desenvolvedores também respondem bem ao feedback, por exemplo, um sistema de integração automatizado revertendo suas alterações se eles tiverem quebrado um teste. Ou melhor, feedback positivo: um sistema de integração automatizado que captura bugs e evita que você quebre as coisas.


Não acho justo dizer que os desenvolvedores são preguiçosos. Talvez seja esse o caso em sua experiência, mas certamente não é uma verdade universal.
Sam

4

Primeiro, se seus desenvolvedores não vêem o valor de seus testes, provavelmente é porque seus testes não são valiosos, não porque seus desenvolvedores são cegos ao seu valor ou ao valor dos testes em geral. Entre seus evangelistas, há uma tendência de acreditar que o desenvolvimento orientado a testes não pode falhar, mas apenas por desenvolvedores preguiçosos. Eu acho que isso é errado e contraproducente.

Quando fui apresentado ao desenvolvimento orientado a testes, isso significou, efetivamente, escrever um teste para verificar se um método que nunca falha nunca falha. O que é legal, a princípio, porque você recebe um lindo cheque verde e uma sensação de realização. Mais tarde, depois de refatorar o código, você tem dezenas de Xes vermelhos irritantes, nenhum dos quais diz mais do que o código foi alterado, que os testes não são mais válidos e que você perdeu muito tempo escrevendo-os.

Você quer evitar isso.

Desde então, adotei uma abordagem diferente para os testes. Em vez de um par de implementação de interface , eu tenho uma interface, implementação, teste triplo . A interface especifica o comportamento, a implementação executa o comportamento, o teste verifica o comportamento.

Suponho que parece óbvio, mas para mim, ele distingue entre o código que você deve provar que funciona como especificado e o código que você pode testar tanto ou pouco quanto considerar apropriado. O código que você deve provar é a interface que você oferece para o exterior; o resto é sua preocupação sozinho.

Nesse caso, eu perguntaria aos desenvolvedores se eles veem uma divisão natural no código em que esse tipo de teste seria apropriado. Existe uma interface que o Time A implementa e o Time B use? Nesse caso, é do interesse da equipe B garantir que a interface se comporte conforme o esperado. Peça à Equipe B para escrever um teste e peça à Equipe A para garantir que sua implementação esteja em conformidade com o teste; ou, se não, e intencionalmente não, discutir a mudança inesperada com a outra equipe, para que eles possam se preparar.

Eu acho que isso ilustraria o valor do teste. Não é um fim em si mesmo, apesar dos adoráveis ​​cheques verdes. Existe para explicitar a promessa feita por um desenvolvedor a outro e para garantir que a promessa seja mantida para a satisfação de ambos.


1
Gosto de código que eu possa ler melhor do que o que alguém sentiu que precisava ser testado até as minúcias assim.
Erik Reppen

1
Os adoráveis ​​ticks verdes que sinto são o problema - transforma os testes em algum tipo de jogo.
gbjbaanb

2

Adicionar muitos testes de unidade a um grande projeto preexistente é um trabalho árduo. Se você já encontrou uma boa estrutura de zombaria que funciona para você, deveria ter resolvido o problema mais difícil.

Sugiro tentar adicionar testes à medida que você adiciona recursos / corrige bugs. A correção de bugs é a mais fácil. Escreva um teste que falhe devido ao seu erro e corrija-o. Ao mesmo tempo, você provavelmente se encontrará escrevendo alguns testes mais simples que passam. Claro que você realmente deseja usar um pequeno e facilmente testado código para isso.

Quando as pessoas começarem a se acostumar a escrever testes para as coisas mais fáceis, esperamos que elas escrevam seu código para serem mais testáveis.

Eu também recomendaria que você medisse a cobertura de código de seus testes (eu usei cobertura para Java no passado). Você precisará de um servidor de integração contínuo executando os testes e produzindo as métricas regularmente (todos os dias, todos os check-in). Se seus colegas desenvolvedores estiverem interessados, eles verão a cobertura aumentar ao longo do tempo e poderão ver os buracos de cobertura em algumas de suas


2

Eu acho que você pode ter que jogar o jogo longo. Uma coisa que você pode fazer para obter alguma aceitação é tentar testar exaustivamente o próximo recurso que você escreve e acompanhar o número de bugs ao longo do tempo. Esperamos que você descubra que os principais erros serão detectados desde o início (principalmente se você associar isso ao design orientado a testes) e o número de regressões deve ser muito baixo. Após um período de tempo, digamos 1 ano, compare as estatísticas com recursos não testados em unidade de complexidade semelhante. Se você puder mostrar que o número de novos bugs e regressões é consideravelmente menor, você forneceu uma justificativa financeira para isso e fica mais difícil para a equipe de produto ignorar.

Eu tive uma situação em que pude usar o TDD e o teste de unidade para um recurso importante. Após o final da fase de desenvolvimento, não houve um único bug relatado em mais de 5 anos. Quando um aprimoramento novo e arriscado foi solicitado, eu pude implementá-lo e capturar todas as regressões nos testes de unidade.


1

É minha opinião forte que o valor dos testes unitários é amplamente subestimado por muitas equipes devido a vários fatores, muitos já destacados nas respostas.

Muitas vezes, os desenvolvedores estão sob pressão para "fazer as coisas", portanto, provar que um bloco de código funciona é uma prova suficiente para o cliente. Isso quase sempre se aplica à empresa de consultoria e ao controle de qualidade humano: se o cliente não precisar de testes de unidade e considerar uma demonstração ao vivo suficiente, o cliente falhará totalmente, pois assinará a aprovação do código que pode ocultar falhas.

Muitas vezes, os desenvolvedores ficam frustrados. Ser um programador é uma tarefa difícil: concluir uma tarefa e passar para a próxima é gratificante, para que todos desejem se apressar e terminar. Até serem atropelados por um ônibus com um bug grave que aumenta meses após o controle de qualidade original. Nesse cenário, o controle de qualidade automatizado e contínuo é um problema de gerenciamento e não de desenvolvedores (eles ainda serão pagos pelo trabalho, talvez horas extras).

Mas há uma exceção

Eu acredito firmemente que a aceitação do modelo de teste automatizado é uma função da "humanidade" dos testes que estão sendo feitos. Se você estiver testando um módulo da Web com um front end, é mais provável, apesar de ferramentas como o Selenium, preencher o formulário sozinho, ver o resultado e acreditar em determinismo. Você esquecerá de executar os testes mais tarde ou ficará com preguiça de fazer testes antigos novamente, e é por isso que os erros às vezes são descobertos mais tarde. Para alavancar isso, uma forte modularização do código e regras estritas sobre "modificar código antigo" foram provadas aceitáveis ​​em um ambiente bancário (na minha experiência pessoal de trabalho).

Em vez disso, se o desenvolvedor estiver encarregado de desenvolver um módulo de dados altamente automatizado e de alto volume, ele provavelmente escreverá testes de unidade completos e os enviará para os lotes de teste. Isso porque o preenchimento de uma grande carga XML com dados convertidos de uma fonte de dados externa (zombada ou não) não é um trabalho propenso a humanos. Alguns desenvolvedores de teste eventualmente criarão um front end minúsculo e engraçado para esse tipo específico de teste. Quando trabalhei na minha tese de mestrado, estava trabalhando em um barramento de log que lidava com mais de 6000 mensagens syslog por segundo e tive que medir a perda e a corrupção de pacotes: naturalmente escrevi testes de unidade e estresse para quase todos os componentes, especialmente o analisador Syslog.

Para tornar os desenvolvedores mais propensos a testes de unidade

Eu acredito que eles devem ser forçados a. Se você é um cliente inteligente, precisará de seus consultores para executar o conjunto completo de testes em cada controle de qualidade. Se você é um bom líder de equipe, pense em atribuir a seguinte tarefa a um desenvolvedor inteligente: crie uma plataforma de teste interno. Isso não tem nada a ver com o antipatter da plataforma de efeito interno, mas, em vez disso, é um conjunto de classes auxiliares, simulações de bancos de dados, configurações, analisadores, conversores, canivetes suíços para ajudar os desenvolvedores a criar testes em pouco tempo.

As plataformas de teste atuais, como o NUnit, são de uso geral e permitem verificar asserções genéricas. O uso correto de injeção de dependência e fábricas específicas do projeto ajuda os desenvolvedores a escrever menos código para testes e a serem mais felizes. Ainda não tive a chance de experimentar isso em um projeto completo, não posso fornecer feedback da vida real.


1

O teste automatizado é como o desenvolvimento de software. Infelizmente, as pessoas que você contrata para testes destinam-se originalmente a escrever casos de teste, planos, estratégia, acompanhar o processo de revisão, testar manualmente e registrar bugs.

Assim que recebem responsabilidades de teste automatizadas, isso inclui uma certa quantidade de desenvolvimento de software. O problema aqui é que os testes automatizados, independentemente de quais ferramentas você usa (e, pelo amor de Deus, não discutem esse ponto), precisam de manutenção e atualização diariamente. À medida que os desenvolvedores alteram o código,

  • você precisa garantir que os testes sejam mantidos em execução.
  • Você precisa garantir que os testes não sejam removidos, pois não foram executados
  • suas métricas de teste precisam mostrar o que você executou na última compilação e nessa compilação. Para garantir que seu número de casos de teste não seja reduzido.
  • os casos de teste precisam ser revisados ​​assim como o desenvolvimento para garantir que as pessoas não estraguem, meio que quebrando 1 teste em 2 apenas para aumentar os números (algumas vezes os testes são terceirizados, portanto, esse rastreamento é importante)
  • muito mais comunicação "saudável" entre desenvolvedor e teste é importante
  • mantenha os non-functionaltestes separados e não espere que eles executem diariamente, leva tempo para mantê-los atualizados e bons. Mas não desista, verifique se eles são mantidos.

Você falhou devido a esses motivos

  • seus engenheiros de teste são engenheiros de teste manuais sem habilidades analíticas. eles não sabem a diferença entre a ife um whileloop. Como francamente nenhum curso ensina testes automatizados, eles apenas ensinam testes manuais.
  • seus engenheiros de teste estão ocupados demais testando manualmente suas compilações e registrando bugs para que eles percam o controle de testes automatizados
  • seus gerentes de teste não se importam com as métricas dos testes automatizados, apenas porque mostram dados inválidos (quando o projeto é iniciado) e não colocam esforço ou prioridade nas apresentações e reuniões diárias para enfatizar a importância de colocar a automação em funcionamento.
  • você escolhe automatizar testes para aplicativos móveis, que têm um prazo de validade muito curto. no momento em que você escrever, estabilize o conjunto de testes automatizados, pois os requisitos de seu aplicativo são alterados. Em vez disso, você deve se concentrar em testar seus serviços da web que executam seu aplicativo
  • você não entende que a equipe de teste automatizada segue o mesmo marco: equipe de desenvolvimento, recurso completo, código completo, bloqueio de código e congelamento de código.
  • você não diferencia entre pessoas de testes manuais e pessoas de testes automatizados.
  • ambos recebem o mesmo salário e se reportam ao mesmo gerente; idealmente, devem se reportar ao gerente de desenvolvimento e seus salários devem corresponder aos do desenvolvimento.
  • você pensa e acredita que junit não é suficiente para desenvolver testes automatizados :).

Isso é da minha experiência trabalhando para empresas que levam muito a sério os testes automatizados e entendem que o desenvolvedor é importante como engenheiros de testes automatizados. E pela minha experiência trabalhando para pessoas que não sabem, entenda a diferença, não importa o quanto você as explique.


No caso de testes de unidade e integração, as pessoas que devem escrever os testes são os desenvolvedores, não os "engenheiros de teste" separados. (Como escrito na pergunta, o controle de qualidade, ou seja, os engenheiros de teste, na verdade já utilizar testes de UI automatizados.)
Paulo Ebermann

Realisticamente falando, qualquer pessoa que escreva testes automatizados deve ter habilidades de desenvolvimento.
Siddharth
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.