TDD e controle de versão


25

Atualmente, estou aprendendo sobre TDD e tentando colocá-lo em prática em meus projetos pessoais. Eu também usei extensivamente o controle de versão em muitos desses projetos. Estou interessado na interação dessas duas ferramentas em um fluxo de trabalho típico, especialmente quando se trata da máxima de manter pequenos compromissos. Aqui estão alguns exemplos que vêm à mente:

  1. Inicio um novo projeto e escrevo um teste simples para criar uma classe ainda não existente. Devo confirmar o teste antes de escrever a classe, mesmo que o teste não seja compilado? Ou devo esboçar a quantidade mínima de código necessária para compilar o teste antes de confirmar?

  2. Encontro um bug e escrevo um teste para recriá-lo. Devo confirmar o teste com falha ou implementar a correção de bug e depois confirmar?

Estes são os dois exemplos que vêm imediatamente à mente. Sinta-se à vontade para fornecer exemplos adicionais em sua resposta.

Editar:

Eu assumi nos dois exemplos que imediatamente após escrever o teste, escreverei o código para fazer o teste passar. Outra situação também pode surgir: eu trabalho em um projeto usando TDD por várias horas sem confirmar. Quando finalmente faço confirmações, quero dividir meu trabalho em pequenos pedaços. (O Git torna isso relativamente fácil, mesmo se você deseja confirmar apenas algumas das alterações em um único arquivo.)

Isso significa que minha pergunta é tanto sobre o que cometer quanto sobre quando cometer.

Respostas:


21

Devo confirmar o teste antes de escrever a classe, mesmo que o teste não seja compilado? Ou devo esboçar a quantidade mínima de código necessária para compilar o teste antes de confirmar?

Claro que não. Você deve terminar o teste e a turma. Cometer algo 1 que nem sequer compila não faz sentido e certamente deixará as pessoas que trabalham no mesmo projeto com raiva se você o fizer regularmente.

Encontro um bug e escrevo um teste para recriá-lo. Devo confirmar o teste com falha ou implementar a correção de bug e depois confirmar?

Não, não faça um teste com falha. A lei da LeBlanc declara:

Mais tarde é igual a nunca.

e seu teste pode falhar por um longo tempo. É melhor corrigir o problema assim que for detectado.

Além disso, o estilo de desenvolvimento TDD diz:

O desenvolvimento orientado a testes repete constantemente as etapas de adição de casos de teste que falham, passam por eles e refatoram.

Se você fizer o check-in de um teste com falha, isso significa que você não concluiu o ciclo.


1 Quando eu disse commit, eu quis dizer realmente comprometer-me com o tronco (para usuários do git, faça suas alterações, para que outros desenvolvedores as obtenham).


4
"e vai certamente fazer povos irritados que trabalham no mesmo projeto se" - alguém está vivendo em SVN mundo usam GIT e você não vai fazer qualquer um irritado
Mateusz

3
Acho que o comprometimento é bom depois de escrever um teste, apenas não faça pressão até terminar.
Matsemann

4
@radarbob Isso se aplica mesmo a um DVCS em que há uma distinção entre confirmar e enviar? Posso imaginar uma situação em que eu faço vários commit no meu repositório git local, onde no commit final o build não está quebrado, mas em qualquer um dos commit intermediários.
Code-Guru

6
Não, não cometa o teste com falha. Mas um dos pontos do TDD é justamente fazer um teste com falha antes da codificação. Portanto, fazer um teste reprovado faz sentido.
Mouviciel

4
@ Code-Guru: Para um DVCS, essas regras devem ser: "Não cometa código quebrado em um ramo do qual outros extraem regularmente". Se outras pessoas não saírem do seu repositório local, isso poderá ocorrer em qualquer estado com o qual você possa conviver.
Bart van Ingen Schenau

6

Devo confirmar o teste antes de escrever a classe, mesmo que o teste não seja compilado?

Não.

Devo cometer o teste que falhou

Não.

Você está falando de dois paradigmas aqui:

  1. desenvolvimento orientado a testes - que não diz nada sobre a confirmação de código. Na verdade, ele mostra como escrever código e quando você termina. Portanto, consideraria todos os 'concluídos' como candidatos a um commit.
  2. desenvolvimento ágil, especificamente: "comprometa-se cedo e frequentemente" (o que não requer TDD). A idéia por trás disso é ter uma integração precoce com outros componentes do sistema e, assim, obter feedback antecipado. Se você cometer em um DVCS localmente e não forçar, é inútil nesse sentido. As confirmações locais apenas ajudam os desenvolvedores a estruturar seu trabalho.

Minha recomendação é: siga o círculo do TDD até que seu código seja compilado, seus testes sejam ecológicos e você tenha algo para contribuir com o sistema. Portanto, você deve cortar seus recursos verticalmente, por exemplo, para uma nova máscara de interface do usuário, não crie todo o formulário e confirme sem a lógica de negócios, mas implemente um aspecto minúsculo, mas no front-end e na lógica de negócios, bem como na camada de persistência .

Para uma correção de bug grande, confirme após cada melhoria (por exemplo, refatoração), mesmo que o bug ainda não tenha sido corrigido. Os testes devem ser verdes e o código deve ser compilado.


5

Certamente você começa usando um controle de fonte saudável como o git.

Depois, você pode trabalhar da maneira que quiser e se comprometer em cada canto - qualquer passo ou subetapa é um jogo justo.

Antes de enviar as coisas, você compila todo o trabalho em um único commit. Ou um casal, em pontos onde tudo é verde e a composição faz sentido. E empurre esses commits sensatos. Para o caso múltiplo, crie um ramo com o qual você mescla --no-ff.

O controle de origem não é um sistema de rastreamento de trabalho ou um historiador. Os commits devem apresentar um delta coerente e sensível, enquanto o estado do checkout deve compilar pelo menos. Os intermediários podem ser preservados por um tempo para fins de revisão, mas quando tudo é considerado bom, um único commit por recurso é justo.


5

É meu entendimento do mundo que se compromete a marcar um ponto ao qual pode ser desejável retornar. O ponto em que um teste falha (mas compila) é definitivamente um desses pontos. Se eu me afastasse na direção errada, tentando passar no teste, gostaria de poder reverter o código de volta ao ponto de partida e tentar novamente; Não posso fazer isso se não tiver cometido.


Eu concordo com você. Prefiro usar um ramo diferente para seguir a regra "não quebre a construção" e mesclar as alterações no tronco somente quando o teste for aprovado.
Fil

5

Devo confirmar o teste antes de escrever a classe, mesmo que o teste não seja compilado?

Com um SCM ramificado (vi você usar o Git), você deve confirmar sempre que quiser um ponto de backup ("eu estraguei tudo; vou redefinir o diretório de trabalho para o último ponto de backup") ou quando você tiver uma versão estável. Quando você possui uma versão estável (todos os testes são aprovados), considere também mesclar o ramo de recursos atual ao ramo de desenvolvimento principal.

Ou devo esboçar a quantidade mínima de código necessária para compilar o teste antes de confirmar?

Depende de você (o git oferece a flexibilidade de se comprometer sempre que você quiser, sem afetar outros membros da sua equipe ou sua capacidade de trabalhar em diferentes recursos). Apenas verifique se você não possui vários recursos incompletos (que não funcionam) na mesma ramificação ao mesmo tempo (eles se bloquearão).

Encontro um bug e escrevo um teste para recriá-lo. Devo confirmar o teste com falha ou implementar a correção de bug e depois confirmar?

Eu costumo fazer dois commits para isso, a menos que o código de teste seja realmente pequeno / trivial para escrever.

Estes são os dois exemplos que vêm imediatamente à mente. Sinta-se à vontade para fornecer exemplos adicionais em sua resposta.

Editar:

Nos dois exemplos, assumi que, imediatamente após escrever o teste, escreverei o código para fazer o teste passar.

Essa poderia ser uma suposição errada a ser feita. Se você trabalha sozinho (projeto pessoal) nada o impede de sempre fazer isso. Em um dos meus projetos mais bem-sucedidos (com relação à manutenção de alta qualidade de código e TDD durante todo o desenvolvimento do projeto), definimos testes algumas vezes semanas antes de implementá-los (ou seja, diríamos "o teste" test_FOO_with_null_first_parameter "agora é definido como uma função vazia e comprometa-o assim). Depois, fazeríamos um sprint (ou meio sprint) algumas vezes um mês depois, apenas para aumentar a cobertura do teste do módulo.Como já tínhamos os testes declarados, era fácil estimar.

Outra situação também pode surgir: eu trabalho em um projeto usando TDD por várias horas sem confirmar. Quando finalmente faço confirmações, quero dividir meu trabalho em pequenos pedaços. (O Git torna isso relativamente fácil, mesmo se você deseja confirmar apenas algumas das alterações em um único arquivo.) Isso significa que minha pergunta é tanto sobre o que confirmar quanto sobre quando confirmar.

Eu diria que definitivamente me comprometo a criar pontos de backup . Isso funciona muito bem para testes exploratórios ("Vou apenas adicionar algumas impressões em toda a base de código, executar e git reset --hardremovê-las quando terminar) e para criação de protótipos.


2
Cuidado ao recomendar git reset --hard. É um dos poucos comandos no git que fará com que você perca o trabalho.
gnash117

2

No meu fluxo de trabalho, sempre que possível, trabalho incerto em um ramo de controle de fonte pessoal. Para que eu possa tentar, falhar, tente novamente, se necessário, até que funcione, e só me comprometa com o projeto maior quando eu tiver um código de trabalho real.

Da perspectiva do TDD, a pergunta "você faz o check-in primeiro?" depende inteiramente do código em que você está trabalhando. Se for um código novo, você não fará o check-in até ter algo que valha a pena fazer o check-in. Mas se for um erro encontrado no código já compilado ou enviado, vale a pena fazer o check-in em um teste para reproduzir o erro, POR SI MESMO. Especialmente se for o fim de um dia útil e você sair do escritório antes de consertar o código.

(Obviamente, se sua loja possui um processo automatizado de criação que morre se algum teste de unidade falhar, talvez você não queira fazer check-in de um teste com falha até corrigir o erro. Mas isso parece uma maneira estranha de trabalhar, pois "encontre e documentar erros "e" corrigir erros "podem ser executados por duas equipes totalmente diferentes.)

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.