Metodologia: Escrevendo testes de unidade para outro desenvolvedor

28

Eu estava pensando em desenvolvimento de software e escrevendo testes de unidade. Eu tenho a seguinte ideia:

Vamos supor que temos pares de desenvolvedores. Cada par é responsável por uma parte do código. Um do par implementa um recurso (código de escrita) e o segundo escreve um teste de unidade para ele. Os testes são escritos após o código. Na minha ideia, eles se ajudam, mas funcionam separadamente. Idealmente, eles trabalhariam em dois recursos de tamanho semelhante e depois trocariam pela preparação do teste.

Eu acho que essa ideia tem algumas vantagens:

  • testes são escritos por alguém que pode ver mais sobre a implementação,
  • o trabalho deve ser feito um pouco mais rápido do que a programação em pares (dois recursos ao mesmo tempo),
  • os testes e o código são responsáveis ​​por isso,
  • o código é testado por pelo menos duas pessoas e
  • talvez procurar erros no código escrito por alguém que está testando seu código daria uma motivação especial para escrever um código melhor e evitar desvios.

Talvez também seja uma boa ideia adicionar outro desenvolvedor para revisão de código entre o desenvolvimento de códigos e testes.

Quais são as desvantagens dessa idéia? Já é descrito como uma metodologia desconhecida para mim e usada no desenvolvimento de software?

PS. Não sou gerente profissional de projetos, mas sei algo sobre processos de desenvolvimento de projetos e conheço as poucas metodologias mais populares - mas essa ideia não me parece familiar.

franiis
fonte
17
Você está apenas descrevendo o controle de qualidade a jusante no nível da unidade. Se você tem pares trabalhando em alguma coisa, já tentou a programação de pares real com o TDD?
jonrsharpe 17/06
9
Isso funcionaria melhor se o gravador de teste fizesse os testes primeiro (escrever o código do esqueleto) e o outro implementasse a funcionalidade. O primeiro estaria no controle do projeto e o outro faria o trabalho pesado. Isso pode funcionar bem se o primeiro souber o que está fazendo e o segundo não se importar em seguir sua liderança o tempo todo. Não conheço um nome para este modo de cooperação. Eu diria .. reivindique! Comece a chamar esse desenvolvimento de Franiis.
Martin Maat
14
Essa crítica não faz sentido, e sua sugestão não resolve esse problema.
jonrsharpe 17/06
5
@franiis Eu vi colegas escreverem assert truecomo testes e chamarem de dia porque todos os testes estavam passando. Um passo importante estava faltando: os testes deveriam falhar primeiro e deveriam passar pela alteração do código, não dos testes.
Eric Duminil 18/06
6
@franiis TDD é construído em torno da iteração. Escreva teste com falha. Escreva um código que torne o teste verde. Refatorar. Escreva um teste com falha. Escreva um código que torne o teste verde. Refatorar. Parece que você está perdendo a parte "repita até ter testes que atendam a todos os seus requisitos". Mas o maior problema que você parece ter é que "testes" são vistos como algo que você deve ter porque alguém disse isso, em vez de os testes serem uma ferramenta útil para os desenvolvedores . Se você não conseguir que as pessoas se preocupem com a qualidade (e a correção) do código, esse é o seu problema e é por onde você deve começar.
Luaan 19/06

Respostas:

30

A abordagem geral do uso de pares para dividir o esforço de escrever código de produção e escrever seus testes de unidade associados não é incomum. Eu até emparelhei pessoalmente dessa maneira antes com sucesso decente. No entanto, uma linha estrita entre a pessoa que escreve o código de produção e a pessoa que escreve o código de teste pode não necessariamente produzir resultados.

Quando usei uma abordagem semelhante, o par começa falando e obtendo um entendimento compartilhado do problema. Se você estiver usando TDD, poderá começar com alguns testes básicos primeiro. Se você não estiver usando TDD, talvez comece com a definição do método. A partir daqui, os dois membros do par trabalham no código de produção e no código de teste, com uma pessoa focando em cada aspecto, mas falando sobre maneiras de melhorar o código de produção e o código de teste por trás dele.

Não vejo a vantagem de dar a cada par dois recursos. Você terminaria com algo que se assemelha ao TDD para alguns recursos e algo que não se aplica a outros recursos. Você perde o foco. Você não obtém os benefícios da revisão por pares em tempo real. Você não obtém nenhum dos principais benefícios do emparelhamento.

A prática da programação em pares não se refere à velocidade, mas à qualidade. Portanto, tentar usar uma técnica modificada impulsionada pelo avanço mais rápido vai contra a natureza. Ao criar software de alta qualidade por meio de revisão de código paralela e desenvolvimento de testes, você economiza tempo no processo, pois há pelo menos duas pessoas com conhecimento de cada alteração e está eliminando (ou reduzindo) os ciclos de espera para revisão e teste por pares.

Thomas Owens
fonte
Obrigado, minha ideia pressupõe que os dois recursos sejam desenvolvidos da mesma maneira (mas os desenvolvedores trocam de papéis) - apenas para esclarecer, não para defender o sentido desse conceito. Gosto da sua resposta e do seu foco na velocidade versus qualidade.
franiis 18/06
Na minha experiência, os custos de retrabalho superam os benefícios dessa abordagem. Prefiro que um par negocie essas tarefas usando 'ping-pong' ou outro método.
neontapir 18/06
3
A prática da programação em pares não se refere à velocidade, mas à qualidade. O par TDD tem a ver com qualidade, que traz velocidade de conclusão e custos mais baixos de desenvolvimento. É apenas nossa indústria aprendendo o que os pedreiros conhecem há milênios: seu muro será construído melhor em menos tempo, com menos esforço e menos custo, se você perder algum tempo configurando primeiro uma linha de cordas e uma regra de pedreiro, e depois arrume seus tijolos, do que se você coloca seu tijolo e tenta se ajustar depois com o nível de bolha e o martelo. E obtenha ajuda com as coisas.
Laurent LA RIZZA
@LaurentLARIZZA Isso parece correto. Suponho que uma maneira melhor de dizer que seria "A prática da programação em pares não é sobre velocidade no agora, mas qualidade e velocidade no futuro". Definitivamente, é uma prática prospectiva encontrar problemas mais cedo, melhorar a robustez do trabalho e compartilhar conhecimento para derrubar silos. Agora, todos eles têm um custo que geralmente recompensa no futuro.
Thomas Owens
@ Thomashowens: Bem, o custo da qualidade é percebido apenas, não é real. Depois que seu teste passa (e você organiza seu código), o cenário descrito por ele é concluído e protegido, e você obtém a confiança de que ele funciona conforme o esperado. Está feito e você pode seguir em frente. Se você seguir em frente sem a certeza de que o código funciona, você acabou de aceitar uma dívida que precisará executar as verificações posteriormente. Custo das dívidas, não a ausência de dívidas. Quero dizer, o "futuro" de que você fala é assim que seu primeiro teste passa.
Laurent LA RIZZA
37

O principal problema da sua ideia é que você não pode simplesmente escrever testes para qualquer código. O código deve ser testável.

Ou seja, você precisa ser capaz de injetar zombarias, separar o bit que deseja testar, acessar o estado que foi alterado e precisa confirmar etc.

A menos que você tenha sorte ou escreva o teste primeiro, as chances de escrever o teste significam reescrever um pouco o código. O que, se você não é a pessoa que escreve o código em primeiro lugar, significará atraso, reuniões, refatoração etc.

Ewan
fonte
Obrigado. mas a crítica comum do TDD é que o código é às vezes / frequentemente escrito para tornar os testes "verdes" - não para ser bom. Se os testes não testarem algum aspecto do código, ele poderá ser omitido no código. Escrever o teste mais tarde pode ajudar nisso (aceito que algumas alterações possam ser necessárias depois de escrever o código, mas os desenvolvedores devem aprender a escrever um código mais testável no futuro).
franiis 17/06
11
@ franiis certeza, o principal problema não é que você escreva os testes depois, é a combinação de fazer isso e não ser a mesma pessoa que escreveu o código.
Ewan
mas se o uso, por exemplo, de programação em pares, consome menos tempo. Se dois desenvolvedores trabalham em um terminal, eles não podem trabalhar de maneira alguma simultaneamente em dois recursos, e minha ideia deve permitir isso (mesmo em escopo limitado). Reuniões para micro-equipe para 2 pessoas não devem ser um fardo real.
franiis 17/06
25
@ franiis: "Se os testes não testarem algum aspecto do código, ele poderá ser omitido no código." - Esse é ponto principal. Os testes são uma codificação dos requisitos na forma de exemplos executáveis. Se não houver teste para ele, não haverá requisito e não deverá haver código para ele .
Jörg W Mittag
3
O outro lado do que o @ JörgWMittag disse seria: se seus testes "não testarem parte importante do código", será necessário corrigi-los. Isso será tão verdadeiro no seu sistema quanto no TDD tradicional.
bta 17/06
15

O principal problema que vejo aqui, no nível da unidade, quando escrevo código, quero compilá-lo, executá-lo e remover os bugs mais óbvios imediatamente - mesmo quando o código está incompleto e sei que a unidade, recurso ou função é apenas parcialmente implementado. E para executar o código de uma unidade, preciso de algum programa que chame a implementação, geralmente um teste de unidade ou pelo menos um teste de unidade parcial. Este não é necessariamente o "estilo TDD do livro"; esse teste pode ser escrito antes ou depois do código em teste.

Quando uma versão da minha unidade está com "recurso completo" e livre de todos os erros que posso encontrar por conta própria, faz sentido entregá-la a uma segunda pessoa e deixá-la escrever testes de unidade adicionais ou revisar meu código . Mas para mim não faz sentido entregá-lo assim que o compilador não mostrar nenhum aviso, que é definitivamente muito cedo, caso eu saiba que tive que explicar detalhadamente ao testador coisas que não funcionam "ainda" ou que funcionam diferente em duas horas, pois ainda estou trabalhando nesse trecho de código. A sobrecarga de comunicação necessária para esse nível de detalhe não seria equilibrada pelos benefícios.

Então, sim, ter um segundo desenvolvedor escrevendo testes de unidade adicionais faz sentido, mas não para escrever exclusivamente os testes de unidade .

Doc Brown
fonte
7

Parece haver a possibilidade de ocorrer qualquer uma das seguintes situações - todas indesejáveis:

Confusão

Como Ewan destacou, a CUT pode precisar ser alterada para torná-la testável. O motivo da mudança nem sempre é óbvio para o desenvolvedor (e pode causar desacordo), e é exatamente por isso que os testes são escritos primeiro.

Contenção

O desenvolvedor A pode ter concluído seu código e desejar testá-lo. O desenvolvedor B também pode estar desenvolvendo e, portanto, pode ser reticente em estacionar seu código para participar dos testes de unidade.

Mudança de contexto

Mesmo que o desenvolvedor B esteja disposto a arquivar seu desenvolvimento para testar o código escrito pelo desenvolvedor A - a mudança na atividade tem um custo.


décadas, é aceito que dobrar a mão-de-obra não reduz pela metade o tempo de desenvolvimento. Considerando os fatores que descrevi acima, é difícil ver como esse arranjo melhoraria as coisas.

Robbie Dee
fonte
4

Quando usado em conjunção com programação de pares e TDD, isso é chamado de padrão de pingue-pongue :

  • A escreve um novo teste e vê que ele falha.
  • B implementa o código necessário para passar no teste.
  • B escreve o próximo teste e vê que falha.
  • A implementa o código necessário para passar no teste.

E assim por diante. A refatoração é feita sempre que surgir a necessidade de quem estiver dirigindo.

Mas você parece propor que os dois programadores codifiquem com computadores diferentes. Para fazer isso separadamente, é necessário ter uma especificação de nível muito baixo. Isso vai contra metodologias ágeis. Toda mudança precisaria ser coordenada. No TDD, você está executando o projeto de baixo nível em tempo real e isso não é um problema. Suponho que sua abordagem exigiria ter algum tipo de esqueleto já codificado.

Enfim: você pode aprender muito testando novas maneiras de fazer as coisas, mesmo que não sejam 100% eficientes. Você pode testá-lo e compartilhar sua experiência de vida real

Borjab
fonte
3

Estou chegando atrasado para esta festa, mas acho que tenho algo a acrescentar.

Já é descrito como uma metodologia desconhecida para mim e usada no desenvolvimento de software?

Você está descrevendo o teste de mesmo nível .

Vamos supor que temos pares de desenvolvedores.

Ah, boa e velha programação de pares .

Cada par é responsável por uma parte do código. Um do par implementa um recurso (código de escrita) e o segundo escreve um teste de unidade para ele. Os testes são escritos após o código. Na minha ideia, eles se ajudam, mas funcionam separadamente.

Isso não é programação em pares.

Idealmente, eles trabalhariam em dois recursos de tamanho semelhante e depois trocariam pela preparação do teste.

Definitivamente, esse é o Teste de Pares. Aqui está um artigo da ACM sobre isso . Eu fiz isso. Eu trabalhei onde era uma parte formal do processo de Revisão por Pares . É útil, mas certamente não pretende ser a primeira linha de teste, e certamente não é a Programação de Pares clássica.

Outro nome para isso é Whitebox Testing . Embora essa definição não se preocupe com quem está realizando os testes, mas com o fato de que o testador consegue ver o funcionamento interno da coisa que está testando, em oposição ao teste da Caixa Preta, onde apenas vê o que acontece e o que sai Caixa preta é normalmente o que o controle de qualidade faz.

A primeira linha de teste está firmemente nas mãos do codificador. Caso contrário, você está me pedindo para não testar meu código, o que eu me recuso a fazer. Venho testando meu código desde os 10 anos de idade. Talvez eu não tivesse testado com testes de unidade sofisticados naquela época, mas meu código foi testado. Foi testado toda vez que eu o executei.

O que eu espero de um testador de mesmo nível são testes que aumentam meus testes. Testes que esclarecem abundantemente os problemas que os pares encontraram com o código quando o revisaram. Ao expressar esses problemas com um teste automatizado, fica mais fácil entender o que eles significam. De fato, tive conversas técnicas com colegas que simplesmente não conseguiam entender o que eu estava falando e então percebi que a melhor maneira de mostrar a eles o problema era escrever um teste de unidade. Isso é teste de pares.

Agora, se você quiser me dar testes escritos antes de eu escrever bem o meu código. Nada como um documento de requisitos tão formal que seja compilado.

candied_orange
fonte
Obrigado pela resposta e me apontando para Peer Testing (vou ler sobre isso).
franiis 19/06
1

Eu fiz DDT (testes orientados ao desenvolvimento, também conhecidos como testes após código), programação em pares e TDD de refator vermelho-verde por vários anos cada. Para responder às suas afirmações ponto a ponto:

testes são escritos por alguém que pode ver mais sobre a implementação

A pessoa que está escrevendo testes precisa conhecer a implementação o mais intimamente possível, para escrever testes com boa cobertura, sem sobredetestar. O exemplo clássico disso é o teste com três entradas, quando duas provariam o que você está tentando testar. Embora eles possam obter familiaridade superficial com o código ao lê-lo, não serão capazes de entender exatamente o que o desenvolvedor original passou para chegar ao estado atual. Portanto, eles terão uma compreensão menos do que ótima do código.

o trabalho deve ser feito um pouco mais rápido que a programação em pares (dois recursos ao mesmo tempo)

Eu não entendo por que você diz isso. Enquanto alguém está escrevendo testes, não está trabalhando em novos recursos. Você não pode magicamente duplicar a capacidade de trabalho de alguém, dando-lhe dois tipos diferentes de trabalho. Na minha experiência, escrever testes geralmente é mais difícil do que escrever código de produção, então você definitivamente não pode trabalhar de maneira produtiva e responsável nos testes de algum código enquanto escreve outro recurso.

os testes e o código são responsáveis ​​por isso

Primeiro, testes são código. Para o código de teste comercial, é quase tão importante quanto o código de produção, pois permite que a empresa altere o software sem medo. Segundo, isso não é diferente de uma pessoa escrevendo os testes e o código de produção, ou mesmo um par escrevendo os dois.

código é testado por pelo menos duas pessoas

Não, é testado apenas pela pessoa que está escrevendo o teste. A menos que você queira usar ainda mais tempo nos testes, nesse caso, por que parar às duas?

talvez procurar erros no código escrito por alguém que está testando seu código daria uma motivação especial para escrever um código melhor e evitar desvios.

Os desenvolvedores (mesmo os mais antigos) têm idéias muito diferentes do que constitui um código "bom". A vantagem de uma pessoa é a maneira perfeitamente válida de outra de chegar ao código de trabalho o mais rápido possível. Esta é uma receita para culpar e jogar o sistema.

TDD de refator vermelho-verde ( na verdade, escrevendo um único teste antes de escrever o código de produção, executando-o, vendo-o falhar, modificando apenas o código de produção , executando o teste novamente, vendo-o ser bem-sucedido e depois refatorando-o e não ignorando ou trocando nenhum dos essas etapas) e as revisões de código funcionam.

l0b0
fonte
Seria mais rápido (presumivelmente) porque você não tem duas pessoas fazendo o "mesmo trabalho" - elas estão fazendo suas próprias coisas e trocando parcialmente.
Jacob Raihle 19/06
@JacobRaihle O emparelhamento não é duas pessoas se desenvolvendo lado a lado sem comunicação. Seriam duas pessoas fazendo o mesmo trabalho. O emparelhamento é realmente eficiente porque duas pessoas estão colaborando em um trabalho. Na minha experiência, o desenvolvimento é tão rápido quanto para programadores individuais (ou seja, pares realizam o trabalho duas vezes mais rápido), o software resultante é de qualidade muito mais alta e o conhecimento foi compartilhado.
l0b0
Estou tentando explicar a lógica por trás do "trabalho deve ser feito um pouco mais rápido", o que pareceu confundir você. O emparelhamento geralmente é mais lento em minha experiência, embora eu ainda ache que vale a pena (preferível ao trabalho individual e ao teste de transferência de OPs). Se for mais rápido para você, tanto melhor.
Jacob Raihle
1

Eu acho que essa ideia tem algumas vantagens:

Vamos percorrê-los um por um.

testes são escritos por alguém que pode ver mais sobre a implementação,

Então, você quer dizer que o primeiro desenvolvedor passou algum tempo escrevendo alguma implementação, que ele não tem certeza de que funciona. Em seguida, outro desenvolvedor vem e escreve testes, baseando seu raciocínio no código, ninguém sabe se está correto e esperando que traga uma vantagem tática em comparação com a escrita de testes apenas com relação ao que o código deve fazer. Se a implementação estiver incorreta, minha opinião é que ela não oferece ajuda para escrever testes.

o trabalho deve ser feito um pouco mais rápido que a programação em pares (dois recursos ao mesmo tempo)

Depois que os dois desenvolvedores terminam o desenvolvimento inicial, ninguém sabe se o código está correto. Isso ainda precisa ser verificado, ninguém pode marcar alguém como concluído e ninguém pode prever quando será feito. Compare isso com o TDD: você escreve o teste primeiro, depois o teste falha e passa com o código. Esse código suporta mais e mais cenários. Isso é um avanço.

Se você progredir em paralelo, o código que pode ser reutilizado nos dois recursos será gravado duas vezes e custará duas vezes mais.

os testes e o código são responsáveis ​​por isso,

Examine a propriedade do código coletivo, conforme proposto pelo XP. Você terá ainda mais pessoas responsáveis ​​pelo código. Se seu objetivo é compartilhar conhecimento entre desenvolvedores, por que você está tentando separá-los?

código é testado por pelo menos duas pessoas

Com par TDD também. Ao emparelhar, as duas pessoas precisam concordar que o código escrito é adequado ou não. Se isso resultar em uma briga, algumas pessoas na equipe têm um problema de ego extraviado.

talvez procurar erros no código escrito por alguém que está testando seu código daria uma motivação especial para escrever um código melhor e evitar desvios.

A procura de erros implica que, em algum momento, você tolerou que eles entrassem. Se eles entrassem, eles passariam despercebidos. Recusar-se a escrever os testes primeiro é dar licença aos erros para entrar.

O canto de corte pode não ser intencional. É para isso que serve a programação de pares. Cada membro do par deve ser instruído com o dever de não deixar o outro cortar os cantos, porque bem, todos nós fazemos isso. Isso requer deixar seu orgulho no armário e levá-lo de volta quando você sair do escritório. Se você espera que seu pessoal seja infalivelmente rigoroso, não está considerando a situação comum e se prepara para o fracasso.

O XP diz explicitamente que todas as práticas do XP são reforçadas entre si, cobrindo os defeitos uma da outra. Você não deve ouvir críticas a nenhuma prática do XP separada das outras. Nenhuma prática é perfeita, o TDD não é perfeito, a programação em pares não é perfeita, a propriedade coletiva do código não é perfeita, mas todos se cobrem.

Laurent LA RIZZA
fonte