Quando você escreve o código “real” no TDD?

johnny 08/19/2017. 11 answers, 20.464 views
tdd

Todos os exemplos que li e vi em vídeos de treinamento têm exemplos simplistas. Mas o que eu não vejo se eu faço o código "real" depois que eu fico verde. Esta é a parte "Refatorar"?

Se eu tiver um objeto bastante complexo com um método complexo, escrevo meu teste e o mínimo para fazê-lo passar (depois da primeira falha, Vermelho). Quando eu volto e escrevo o código real? E quanto código real escrevo antes de voltar a testar? Eu estou supondo que o último é mais intuição.

Edit: Obrigado a todos que responderam. Todas as suas respostas me ajudaram imensamente. Parece haver idéias diferentes sobre o que eu estava perguntando ou confuso, e talvez haja, mas o que eu estava perguntando era, digamos que eu tivesse um pedido de construção de uma escola.

No meu design, tenho uma arquitetura com a qual quero começar, User Stories, e assim por diante. A partir daqui, pego essas Estórias de Usuário e crio um teste para testar a História do Usuário. O usuário diz: Temos pessoas que se matriculam para a escola e pagam taxas de inscrição. Então, penso em uma maneira de fazer isso falhar. Ao fazer isso, desenvolvo uma classe de teste para a classe X (talvez Student), que falhará. Eu então criei a classe "Student". Talvez "escola" eu não sei.

Mas, em qualquer caso, o TD Design está me forçando a pensar na história. Se eu posso fazer um teste falhar, sei por que ele falha, mas isso pressupõe que eu possa fazê-lo passar. É sobre o design.

Eu comparo isso a pensar em recursão. Recursão não é um conceito difícil. Pode ser mais difícil controlar isso na sua cabeça, mas na realidade, a parte mais difícil é saber, quando a recursão "quebra", quando parar (minha opinião, é claro). Então eu tenho que pensar sobre o que para a recursão primeiro. É apenas uma analogia imperfeita e presume que cada iteração recursiva é uma "passagem". Mais uma vez, apenas uma opinião.

Na implementação, a escola é mais difícil de ver. Registros numéricos e bancários são "fáceis", no sentido de que você pode usar aritmética simples. Eu posso ver a + b e retornar 0, etc. No caso de um sistema de pessoas, eu tenho que pensar mais sobre como implement isso. Eu tenho o conceito de falha, aprovação, refatoração (principalmente por causa do estudo e dessa questão).

O que eu não sei é baseado na falta de experiência, na minha opinião. Eu não sei como deixar de inscrever um novo aluno. Eu não sei como falhar alguém digitando um sobrenome e sendo salvo em um banco de dados. Eu sei como fazer um + 1 para matemática simples, mas com entidades como uma pessoa, eu não sei se estou apenas testando para ver se eu recebo de volta um ID único do banco de dados ou outra coisa quando alguém insere um nome em um banco de dados ou ambos ou nenhum.

Ou talvez isso mostre que ainda estou confuso.

5 Comments
187 hobbs 07/25/2017
Depois do TDD, as pessoas vão para casa a noite.
14 Goyo 07/25/2017
Por que você acha que o código que você escreveu não é real?
2 johnny 07/26/2017
@RubberDuck Mais do que as outras respostas. Tenho certeza de que vou me referir a ela em breve. Ainda é meio estranho, mas não vou desistir disso. O que você disse faz sentido. Eu só estou tentando fazer sentido no meu contexto ou um aplicativo de negócios regular. Talvez um sistema de inventário ou algo parecido. Eu tenho que considerar isso. Eu sou grato pelo seu tempo embora. Obrigado.
1 Edmund Reed 07/26/2017
As respostas já acertaram na cabeça, mas enquanto todos os seus testes estiverem passando, e você não precisa de nenhum novo teste / funcionalidade, pode-se presumir que o código que você tem está acabado, barra de linting.
3 Borjab 07/26/2017
Há uma suposição na questão que pode ser problemática em "Eu tenho um objeto bastante complexo com um método complexo". Em TDD você escreve seus testes primeiro, então você começa com um código bastante simples. Isso forçará você a codificar uma estrutura de teste que precisará ser modular. Então, um comportamento complexo será criado pela combinação de objetos mais simples. Se você terminar com um objeto ou método bastante complexo, será quando refatorar

11 Answers


RubberDuck 07/27/2017.

Se eu tiver um objeto bastante complexo com um método complexo, escrevo meu teste e o mínimo para fazê-lo passar (depois da primeira falha, Vermelho). Quando eu volto e escrevo o código real? E quanto código real escrevo antes de voltar a testar? Eu estou supondo que o último é mais intuição.

Você não "volta" e escreve "código real". É tudo código real. O que você faz é voltar e adicionar outro teste que o forces a change seu código para fazer o novo teste passar.

Quanto ao código que você escreve antes de voltar a testar? Nenhum. Você escreve código zero sem um teste de falha que o forces a escrever mais código.

Observe o padrão?

Vamos percorrer (outro) exemplo simples na esperança de que isso ajude.

 Assert.Equal("1", FizzBuzz(1)); 

Fácil peazy.

 public String FizzBuzz(int n) {
    return 1.ToString();
} 

Não o que você chamaria de código real, certo? Vamos adicionar um teste que force uma mudança.

 Assert.Equal("2", FizzBuzz(2)); 

Nós poderíamos fazer algo bobo como if n == 1 , mas vamos pular para a solução sã.

 public String FizzBuzz(int n) {
    return n.ToString();
} 

Legal. Isso funcionará para todos os números não-FizzBuzz. Qual é a próxima entrada que irá forçar o código de produção a mudar?

 Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
} 

E de novo. Escreva um teste que não passará ainda.

 Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
} 

E agora cobrimos todos os múltiplos de três (que também não são múltiplos de cinco, vamos anotar e voltar).

Ainda não escrevemos um teste para "Buzz", então vamos escrever isso.

 Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
} 

E novamente, sabemos que há outro caso que precisamos lidar.

 Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
} 

E agora podemos lidar com todos os múltiplos de 5 que também não são múltiplos de 3.

Até este ponto, ignoramos a etapa de refatoração, mas vejo alguma duplicação. Vamos limpar isso agora.

 private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Legal. Agora nós removemos a duplicação e criamos uma função bem nomeada. Qual é o próximo teste que podemos escrever que nos forçará a mudar o código? Bem, temos evitado o caso em que o número é divisível por ambos 3 e 5. Vamos escrever agora.

 Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Os testes passam, mas temos mais duplicação. Temos opções, mas vou aplicar "Extrair Variável Local" algumas vezes para refatorar em vez de reescrever.

 public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

E cobrimos todas as contribuições razoáveis, mas e quanto à entrada unreasonable ? O que acontece se passarmos 0 ou um negativo? Escreva esses casos de teste.

 public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Isso está começando a parecer "código real" ainda? Mais importante, em que ponto deixou de ser "código irreal" e transição para ser "real"? Isso é algo para refletir sobre ...

Então, eu fui capaz de fazer isso simplesmente procurando por um teste que eu sabia que não passaria em cada etapa, mas eu tive muita prática. Quando estou no trabalho, as coisas nem sempre são tão simples e nem sempre sei que teste vai forçar uma mudança. Às vezes, escrevo um teste e fico surpreso ao ver que ele já passa! Eu recomendo que você crie o hábito de criar uma "Lista de teste" antes de começar. Esta lista de testes deve conter todas as entradas "interessantes" que você pode imaginar. Você pode não usá-los todos e provavelmente incluirá os casos, mas essa lista serve como um roteiro. Minha lista de testes para o FizzBuzz seria algo como isto.

  • Negativo
  • Zero
  • 1
  • Dois
  • Três
  • Quatro
  • Cinco
  • Seis (múltiplo não trivial de 3)
  • Nove (3 ao quadrado)
  • Dez (múltiplo não trivial de 5)
  • 15 (múltiplo de 3 e 5)
  • 30 (múltiplo não trivial de 3 e 5)
5 comments
3 maple_shaft♦ 07/27/2017
Comentários não são para discussão extensa; esta conversa foi movida para o bate-papo .
40 GManNickG 07/27/2017
A menos que eu esteja completamente entendendo mal esta resposta: "Nós poderíamos fazer algo bobo como se n == 1, mas vamos pular para a solução sensata". - a coisa toda foi boba. Se você souber de antemão que quer uma função que faça <spec>, escreva testes para <spec> e pule a parte onde você escreve versões que obviamente falham <spec>. Se você encontrar um bug em <spec>, certifique-se de escrever um teste primeiro para verificar se pode exercitá-lo antes da correção e observar se o teste passa após a correção. Mas não há necessidade de falsificar todos esses passos intermediários.
15 user3791372 07/28/2017
Os comentários que apontam as principais falhas nesta resposta e o TDD em geral foram movidos para o chat. Se você está pensando em usar o TDD, por favor leia o 'chat'. Infelizmente, os comentários de 'qualidade' agora estão escondidos entre uma carga de bate-papo para os futuros alunos lerem.
nbro 07/28/2017
Eu seria mais preciso em relação ao conteúdo desta "lista de teste", se você quisesse melhorar essa resposta. Eu explicitamente falaria sobre "valores de limite" e "particionamento de classe".
2 hvd 07/30/2017
@GManNickG Acredito que o objetivo seja obter a quantidade certa de testes. Escrever os testes antecipadamente faz com que seja fácil perder os casos especiais que devem ser testados, levando a que as situações não sejam cobertas adequadamente nos testes ou, essencialmente, a mesma situação sendo carregada inutilmente de vezes nos testes. Se você puder fazer isso sem essas etapas intermediárias, ótimo! Nem todo mundo pode fazer isso ainda, é algo que requer prática.

GenericJon 07/24/2017.

O código "real" é o código que você escreve para fazer seu teste passar. Really É simples assim.

Quando as pessoas falam sobre escrever o mínimo para tornar o teste verde, isso significa apenas que o seu código real deve seguir o princípio YAGNI .

A ideia do passo do refatorador é apenas para limpar o que você escreveu, uma vez que você está feliz que ele atende aos requisitos.

Contanto que os testes que você escreve realmente envolvam os requisitos do seu produto, uma vez que eles estejam passando, o código estará completo. Pense nisso, se todos os seus requisitos de negócios tiverem um teste e todos esses testes forem verdes, o que mais há para escrever? (Ok, na vida real não tendemos a ter cobertura de teste completa, mas a teoria é boa.)

5 comments
44 Derek Elkins 07/24/2017
Os testes unitários não podem, na verdade, abranger seus requisitos de produto, mesmo para requisitos relativamente triviais. Na melhor das hipóteses, eles amostram o espaço de entrada-saída e a ideia é que você (corretamente) generalize para o espaço total de entrada-saída. É claro, o seu código poderia ser apenas um grande switch com um caso para cada teste de unidade que passaria por todos os testes e falharia por quaisquer outras entradas.
8 Taemyr 07/25/2017
Os mandatos do @DerekElkins TDD falham nos testes. Não falhando testes unitários.
6 jonrsharpe 07/25/2017
@DerekElkins é por isso que você não apenas escreve testes de unidade, e também porque há uma suposição geral de que você está tentando fazer algo e não apenas fingir!
35 Derek Elkins 07/25/2017
@jonrsharpe Por essa lógica, eu nunca escreveria implementações triviais. Por exemplo, no exemplo FizzBuzz na resposta da RubberDuck (que usa apenas testes unitários), a primeira implementação claramente "apenas a falsifica". Meu entendimento da questão é exatamente essa dicotomia entre escrever código que você sabe que é incompleto e código que você realmente acredita que implementará o requisito, o "código real". Meu "grande switch " foi planejado como um extremo lógico de "escrever o mínimo para tornar os testes verdes". Eu vejo a pergunta do OP como: onde em TDD é o princípio que evita essa grande switch ?
2 Luaan 07/25/2017
@GenericJon Isso é um pouco otimista demais na minha experiência :) Por um lado, há pessoas que gostam de trabalho repetitivo sem sentido. Eles ficarão mais felizes com uma afirmação de switch gigante do que com uma "tomada de decisão complicada". E para perder o emprego, eles precisam de alguém que os apele à técnica (e é melhor que tenham boas evidências de que estão realmente perdendo as oportunidades / dinheiro da empresa!) Ou que se saiam excepcionalmente mal. Depois de assumir a manutenção em muitos desses projetos, posso dizer que é fácil para um código muito ingênuo durar décadas, desde que faça o cliente feliz (e pagando).

Carl Raymond 07/24/2017.

A resposta curta é que o "código real" é o código que faz o teste passar. Se você puder fazer seu teste passar com algo diferente de código real, adicione mais testes!

Concordo que muitos tutoriais sobre o TDD são simplistas. Isso funciona contra eles. Um teste muito simples para um método que, digamos, computa 3 + 8, não tem outra escolha senão também computar 3 + 8 e comparar o resultado. Isso faz com que pareça que você estará duplicando todo o código, e que o teste é um trabalho extra sem sentido e propenso a erros.

Quando você é bom em testes, isso informará como você estrutura seu aplicativo e como você escreve seu código. Se você tiver problemas para fazer testes úteis e sensatos, provavelmente deve repensar seu design um pouco. Um sistema bem projetado é fácil de testar - o que significa que testes sensatos são fáceis de serem pensados ​​e implementados.

Quando você escreve seus testes primeiro, observa-os falhar e, em seguida, escreve o código que os faz passar, isso é uma disciplina para garantir que todo o seu código tenha testes correspondentes. Eu não cumpro servilmente essa regra quando estou codificando; muitas vezes escrevo testes depois do fato. Mas fazer testes primeiro ajuda a manter você honesto. Com alguma experiência, você começará a perceber quando estiver se transformando em um canto, mesmo quando não estiver escrevendo testes primeiro.

4 comments
6 Steve Jessop 07/26/2017
Pessoalmente, o teste que eu escreveria seria assertEqual(plus(3,8), 11) , não assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)) . Para casos mais complexos, você sempre procura um meio de provar o resultado correto, other than calcular dinamicamente o resultado correto no teste e verificar a igualdade.
Steve Jessop 07/26/2017
Então, para uma maneira realmente boba de fazer isso para este exemplo, você pode provar que plus(3,8) retornou o resultado correto subtraindo 3 dele, subtraindo 8 daquele e verificando o resultado contra 0. Isso é tão obviamente equivalente a assertEqual(plus(3,8), 3+8) como um pouco absurdo, mas se o código em teste está construindo algo mais complicado do que apenas um inteiro, então pegar o resultado e verificar se cada parte está correta é a abordagem correta. Alternativamente, algo como for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop 07/26/2017
... desde que evita o grande medo, que é que ao escrever o teste, vamos cometer o mesmo erro no assunto de "como adicionar 10" que fizemos no código ao vivo. Portanto, o teste evita cuidadosamente escrever qualquer código que adicione 10 a qualquer coisa, no teste que plus() pode adicionar 10 a coisas. Ainda dependemos dos valores do loop interno verificados pelo programador, é claro.
3 Warbo 07/28/2017
Só quero ressaltar que, mesmo que você esteja escrevendo testes depois do fato, ainda é uma boa idéia vê-los falhar; encontre alguma parte do código que pareça crucial para o que você estiver trabalhando, ajuste-o um pouco (por exemplo, substitua um + por um -, ou o que for), execute os testes e observe-os falharem, desfazer a alteração e observá-los. Muitas vezes eu fiz isso, o teste não falha, tornando-o pior do que inútil: não apenas não está testando nada, está me dando uma falsa confiança de que algo está sendo testado!

Victor Cejudo 07/25/2017.

Às vezes, alguns exemplos sobre o TDD podem ser enganosos. Como outras pessoas já apontaram antes, o código que você escreve para fazer os testes passarem é o código real.

Mas não pense que o código real parece mágica - isso está errado. Você precisa entender melhor o que deseja alcançar e, em seguida, precisa escolher o teste de forma adequada, começando pelos casos mais fáceis e pelos casos de canto.

Por exemplo, se você precisa escrever um léxico, você começa com uma string vazia, depois com um monte de espaços em branco, um número, então com um número cercado por espaços em branco, um número errado etc. Essas pequenas transformações levarão você a o algoritmo certo, mas você não pula do caso mais fácil para um caso altamente complexo escolhido de forma idiota para obter o código real feito.

Bob Martin explica isso perfeitamente aqui .


CandiedOrange 07/25/2017.

A parte do refatorado é limpa quando você está cansado e quer ir para casa.

Quando você está prestes a adicionar um recurso, a parte do refatorador é o que você altera antes do próximo teste. Você refatora o código para liberar espaço para o novo recurso. Você faz isso quando know qual será esse novo recurso. Não quando você está apenas imaginando.

Isso pode ser tão simples quanto renomear GreetImpl para GreetWorld antes de criar uma classe GreetMom (depois de adicionar um teste) para adicionar um recurso que irá imprimir "Hi Mom".


graeme 07/27/2017.

Mas o código real apareceria no estágio de refatoração da fase TDD. Ou seja, o código que deve fazer parte da versão final.

Os testes devem ser executados toda vez que você fizer uma alteração.

O lema do ciclo de vida do TDD seria: REFADOR VERDE VERMELHO

RED : Escreva os testes

GREEN : Faça uma tentativa honesta de obter código funcional que passe nos testes o mais rápido possível: código duplicado, variáveis ​​obscuramente chamadas de hacks da mais alta ordem, etc.

REFACTOR : Limpe o código, nomeie corretamente as variáveis. DRY o código.

5 comments
5 mcottle 07/25/2017
Eu sei o que você está dizendo sobre a fase "Verde", mas isso implica que os valores de retorno da fiação para fazer os testes passarem podem ser apropriados. Na minha experiência, "Verde" deve ser uma tentativa honesta de fazer código de trabalho para atender ao requisito, pode não ser perfeito, mas deve ser tão completo e "entregável" como o desenvolvedor pode gerenciar em uma primeira passagem. A refatoração é provavelmente melhor feita algum tempo depois de você ter feito mais desenvolvimento e os problemas com o primeiro passe se tornarem mais aparentes e as oportunidades de DRY emergirem.
graeme 07/25/2017
@ Miscelânea eu considero todos estes parte da mesma tarefa. faça-o, depois limpe-o. Refatorações adicionais devem ocorrer com o passar do tempo como parte de outras tarefas.
1 Bryan Boettcher 07/25/2017
@mcottle: você pode se surpreender com quantas implementações de um repositório get-only podem ser valores codificados na base de código. :)
6 Kaz 07/25/2017
Por que eu sempre escreveria códigos e limparia tudo, quando eu conseguisse código de qualidade de produção quase tão rápido quanto eu pudesse digitar? :)
1 Kaz 07/27/2017
@TimothyTruckle O que leva 50 minutos para encontrar a mudança mais simples possível, mas apenas 5 para encontrar a segunda mudança mais simples possível? Nós vamos com o segundo mais simples ou continuamos procurando por mais simples?

Timothy Truckle 07/27/2017.

Quando você escreve o código “real” no TDD?

A fase red é onde você write código.

Na fase de refactoring , o objetivo principal é delete código.

Na fase red você faz qualquer coisa para fazer o teste passar o as quick as possible e at any cost . Você ignora completamente o que você já ouviu falar de boas práticas de codificação ou padrões de design semelhantes. Fazer o teste verde é tudo que importa.

Na fase de refactoring , você limpa a bagunça que acabou de fazer. Agora você primeiro olha se a mudança que você acabou de fazer é o tipo do topo mais na lista de prioridade de transformação e se houver qualquer duplicação de código, você pode remover o mais provável, aplicando um padrão de design.

Finalmente, você melhora a legibilidade renomeando identificadores e extrai magic numbers e / ou seqüências literais para constantes.


Não é refator vermelho, é refator vermelho-verde. - Rob Kinyon

Obrigado por apontar isso.

Então é a fase green onde você escreve o real code

Na fase red você escreve a executable specification ...

2 comments
Rob Kinyon 07/27/2017
Não é refator vermelho, é refator vermelho-verde. O "vermelho" é que você leva o conjunto de testes de verde (todos os testes passam) para vermelho (um teste falha). O "verde" é o lugar onde você pega a suíte de testes de vermelho (um teste falha) para verde (todos os testes são aprovados). O "refatorador" é onde você pega seu código e o deixa bonito, enquanto mantém todos os testes passando.
Timothy Truckle 07/27/2017
@RobKinyon Obrigado, atualizou a resposta.

Robert Andrzejuk 07/27/2017.

Você está escrevendo o Real Code o tempo todo.

Em cada passo você está escrevendo código para satisfazer as condições que seu código irá satisfazer para futuros chamadores do seu código (que pode ser você ou não ...).

Você acha que não está escrevendo código útil ( real ), porque em um momento você pode refatorar isso.

O Code-Refactoring é o processo de reestruturação do código de computador existente - alterando o factoring - sem alterar o seu comportamento externo.

O que isto significa é que mesmo que você esteja mudando o código, as condições que o código satisfez, são deixadas inalteradas. E as verificações ( tests ) que você implementou para verificar se o seu código já está lá para verificar se suas modificações mudaram alguma coisa. Então o código que você escreveu o tempo todo está lá, apenas de uma maneira diferente.

Outro motivo Você pode pensar que não é um código real, é que você está fazendo exemplos onde o programa final já pode ser previsto por você. Isso é muito bom, como mostra Você tem conhecimento sobre o domain você está programando.
Mas muitas vezes os programadores estão em um domain new , unknown para eles. Eles não sabem qual será o resultado final e TDD é uma technique para escrever programas passo a passo, documentando nosso knowledge sobre como esse sistema deve funcionar e verificando se nosso código funciona dessa maneira.

Quando li The Book (*) no TDD, para mim a característica mais importante que se destacou foi a lista: TODO. Isso me mostrou que o TDD também é uma técnica para ajudar os desenvolvedores a se concentrarem em uma coisa por vez. Portanto, esta é também uma resposta à sua pergunta sobre How much Real code to write ? Eu diria código suficiente para se concentrar em uma coisa de cada vez.

(*) "Test Driven Development: por exemplo" por Kent Beck

1 comments
2 Robert Andrzejuk 07/27/2017
"Test Driven Development: por exemplo" por Kent Beck

Zenilogix 07/31/2017.

Você não está escrevendo código para fazer seus testes falharem.

Você escreve seus testes para definir como deve ser o sucesso, o que deve inicialmente falhar porque você ainda não escreveu o código que irá passar.

A questão toda sobre escrever testes iniciais é fazer duas coisas:

  1. Cobrir todos os casos - todos os casos nominais, todos os casos de borda, etc.
  2. Valide seus testes. Se você só os vê passar, como pode ter certeza de que eles relatarão uma falha de maneira confiável quando ocorrer um?

O ponto por trás do refator vermelho-verde é que escrever os testes corretos primeiro dá a você a confiança de saber que o código que você escreveu para passar nos testes está correto e permite refatorar com a confiança de que seus testes o informarão assim que algo quebra, então você pode imediatamente voltar e consertar.

Na minha própria experiência (C # / .net), teste puro primeiro é um pouco inatingível ideal, porque você não pode compilar uma chamada para um método que ainda não existe. Portanto, "teste primeiro" é realmente sobre como codificar interfaces e implementações de stub primeiro, depois escrever testes contra os stubs (que inicialmente falharão) até que os stubs sejam apropriadamente desenvolvidos. Eu nunca estou escrevendo "código de falha", apenas construindo a partir de tocos.


Zan Lynx 07/27/2017.

Eu acho que você pode estar confuso entre testes de unidade e testes de integração. Eu acredito que também pode haver testes de aceitação, mas isso depende do seu processo.

Depois de testar todas as pequenas "unidades", você as testa todas reunidas ou "integradas". Isso geralmente é um programa ou biblioteca inteira.

No código que escrevi, a integração testa uma biblioteca com vários programas de teste que leem dados e os alimentam para a biblioteca, depois verificam os resultados. Então eu faço com threads. Então eu faço com threads e fork () no meio. Então eu corro e mato -9 após 2 segundos, então eu inicio e verifico o modo de recuperação. Eu confuso isso. Eu o torturo de todos os modos.

Tudo isso também está testando, mas eu não tenho uma tela vermelha / verde bonita para os resultados. Ou consegue, ou eu cavo através de alguns milhares de linhas de código de erro para descobrir o porquê.

É aí que você testa o "código real".

E eu apenas pensei nisso, mas talvez você não saiba quando você deveria terminar de escrever testes de unidade. Você termina de escrever testes de unidade quando seus testes exercitam tudo o que você especificou que deveria fazer. Às vezes, você pode perder a noção disso entre todos os casos de tratamento de erros e de borda, então você pode querer fazer um bom grupo de teste de testes de caminho feliz que simplesmente vá direto às especificações.

1 comments
Peter Mortensen 07/27/2017
(é = possessivo, é = "é" ou "tem". Veja por exemplo How to Use Its and It's .)

user3791372 07/27/2017.

Em resposta ao título da pergunta: "Quando você escreve o código" real "em TDD?", A resposta é: "quase nunca" ou "muito lentamente".

Você parece um estudante, então eu responderei como se estivesse aconselhando um aluno.

Você vai aprender muitas 'teorias' e 'técnicas' de codificação. Eles são ótimos para passar o tempo em cursos de estudante superfaturados, mas de muito pouco benefício para você que você não pode ler em um livro na metade do tempo.

O trabalho de um codificador é unicamente para produzir código. Código que funciona muito bem. É por isso que você, o programador planeja o código em sua mente, no papel, em um aplicativo adequado, etc., e planeja trabalhar com antecedência possíveis falhas / falhas, pensando lógica e lateralmente antes da codificação.

Mas você precisa saber como quebrar seu aplicativo para poder criar código decente. Por exemplo, se você não conhecesse Little Bobby Table (xkcd 327), provavelmente não estaria higienizando suas entradas antes de trabalhar com o banco de dados, portanto, não conseguiria proteger seus dados em torno desse conceito.

TDD é apenas um fluxo de trabalho projetado para minimizar os erros em seu código, criando os testes do que poderia dar errado antes de codificar seu aplicativo, pois o código pode ficar exponencialmente difícil quanto mais código você introduzir e se esquecer de bugs que você pensou. Uma vez que você acha que terminou sua aplicação, você executa os testes e o boom, esperamos que os erros sejam detectados nos seus testes.

O TDD não é - como algumas pessoas acreditam - escrever um teste, fazê-lo passar com um código mínimo, escrever outro teste, obter esse código com código mínimo, etc. Em vez disso, é uma forma de ajudar você a codificar com confiança. Esse ideal de código contínuo de refatoração para fazê-lo funcionar com testes é idiota, mas é um conceito interessante entre os alunos, pois faz com que eles se sintam bem quando adicionam um novo recurso e ainda estão aprendendo a codificar ...

Por favor, não caia nessa armadilha e veja o seu papel de codificação para o que é - o trabalho de um codificador é unicamente para produzir código. Código que funciona muito bem. Agora, lembre-se de que você estará no relógio como um codificador profissional, e seu cliente não se importará se você escreveu 100.000 asserções, ou 0. Eles só querem código que funcione. Muito bem, na verdade.

5 comments
3 johnny 07/25/2017
Não estou nem perto de um aluno, mas leio e tento aplicar boas técnicas e ser profissional. Então, nesse sentido, eu sou um "estudante". Eu só faço perguntas básicas, porque é assim que eu sou. Eu gosto de saber exatamente porque estou fazendo o que estou fazendo. O coração da matéria. Se eu não entendi, não gosto e começo a fazer perguntas. Eu preciso saber por que, se eu vou usá-lo. O TDD parece intuitivamente bom em alguns aspectos, como saber o que você precisa criar e pensar, mas a implementação era difícil de entender. Acho que entendo melhor agora.
4 Sean Burton 07/27/2017
Essas são as regras do TDD. Você é livre para escrever o código como quiser, mas se você não seguir essas três regras, não estará fazendo TDD.
2 user3791372 07/27/2017
"Regras" de uma pessoa? TDD é uma sugestão para ajudá-lo a codificar, não uma religião. É triste ver tantas pessoas aderindo a uma ideia tão anal. Até mesmo a origem do TDD é controversa.
2 Alex 07/28/2017
@ user3791372 O TDD é um processo muito rigoroso e claramente definido. Mesmo que muitos pensem que é apenas dizer "Faça algum teste quando você está programando", não é. Vamos tentar não misturar termos aqui, essa questão é sobre o processo TDD, não o teste geral.

Related questions

Hot questions

Language

Popular Tags