TDD - Curva de aprendizado

49 respostas
N

Pessoal, iniciei há algumas semanas o meu primeiro emprego em desenvolvimento Java e na empresa desenvolvemos usando TDD. Tive o primeiro contato com TDD nos últimos dias e estou com grande dificuldades em assimilar, ou melhor, de pensar e desenvolver com TDD. E o aprendizado ficará por minha conta, vou ter que correr atrás.

Gostaria de saber dos colegas se vcs também enfrentaram dificuldades com TDD e se demorou muito tempo para vocês desenvolveram naturalmente usando TDD?

49 Respostas

H

Leia um livro.

É o melhor que você pode fazer. Tem o da casa do Código, tem também o JUnit in Action e o TDD Kent Beck (que é um dos idealizadores).

N

Hebert Coelho:
Leia um livro.

É o melhor que você pode fazer. Tem o da casa do Código, tem também o JUnit in Action e o TDD Kent Beck (que é um dos idealizadores).

O livro da casa do código sobre TDD já tenho e estou lendo no momento :slight_smile: Inclusive o seu livro sobre JSF já está na minha lista de leitura. Vou procurar esse do Kent Beck.

H

norbAns:
Hebert Coelho:
Leia um livro.

É o melhor que você pode fazer. Tem o da casa do Código, tem também o JUnit in Action e o TDD Kent Beck (que é um dos idealizadores).

O livro da casa do código sobre TDD já tenho e estou lendo no momento :slight_smile: Inclusive o seu livro sobre JSF já está na minha lista de leitura. Vou procurar esse do Kent Beck.

Uia, valeu.

TDD é com conceito de louco (a primeiro momento). Depois que se pega a prática é possível ver que tudo fica mais fácil.

Só de você fazer um código e rodar o teste na hora já é muito bom. Você sabe onde e como vai impactar.

V

Você pode ler sobre os conceitos, mas não vai aprender a fazê-lo lendo livros.

Pratique muito, vá em dojos, code com pessoas que já tem prática. Quanto mais você praticar tdd, mais rápido vai dominá-la. Dojos são excelentes ambientes para tal. Você também pode fazer um curso, um instrutor pode te passar várias manhas, mas novamente, você precisa praticar muito.

Y

Hebert Coelho:
norbAns:
Hebert Coelho:
Leia um livro.

É o melhor que você pode fazer. Tem o da casa do Código, tem também o JUnit in Action e o TDD Kent Beck (que é um dos idealizadores).

O livro da casa do código sobre TDD já tenho e estou lendo no momento :slight_smile: Inclusive o seu livro sobre JSF já está na minha lista de leitura. Vou procurar esse do Kent Beck.

Uia, valeu.

TDD é com conceito de louco (a primeiro momento). Depois que se pega a prática é possível ver que tudo fica mais fácil.

Só de você fazer um código e rodar o teste na hora já é muito bom. Você sabe onde e como vai impactar.


Concordo com o Herbert.

Como eu sempre digo, TDD eh muito simples, se está complicado é porque os conceitos de responsabilidade, desacoplamento, coesão e as coisas mais básicas de orientação a objetos ainda não estão claras na sua cabeça.

Implementar TDD não é fácil, mas porque OO não é fácil, embora pareça a princípio.

Parodiando uma frase atribuida a Descartes: Conhecimento em Orientação a Objetos é a coisa mais bem distribuída entre os programadores, ninguém acha que precisa mais do que já tem.

Estude Orientação a Objetos, muito e um pouco de TDD que as coisas saem naturalmente.

M

Sinceramente, o melhor jeito de aprender TDD é pair programming (Com alguém mais experiente).

X

Hebert Coelho:
Leia um livro.

É o melhor que você pode fazer. Tem o da casa do Código, tem também o JUnit in Action e o TDD Kent Beck (que é um dos idealizadores).

Concordo! Durante muito tempo achei que TDD era sinônimo de testes unitários, de implementar e ai criar um testes e somente entendi o conceito depois de ler o livro do Kent Beck (Desenvolvimento Guiado Por Testes). Já nos primeiro capítulos desse livro e vi que fazia tudo errado e me deu um está-lo.

O único problema que vejo de TDD é que você tem que entender bem de OOP, senão não vai ter como, pois para aplicar TDD efetivamente você terá que criar classes com baixissimo acoplamentos, pois classes muitos acopladas demandam um uso excessivo de Mocks que dificultam em muito o desenvolvimento. Com TDD você vai ganhar alta coesão de suas classes pois vai implementar somente o que elas realmente devem fazer.

X

Discordo, acho que os conceitos são importantes

Ai eu já concordo, acredito que lendo e colocando em prática você começara a ter o dominio do TDD

Eu aprendi sozinho! Assim que comecei a ler o livro do Kent comecei a colocar em prática os conceitos e como o livro é muito simples é rápido de ler e praticar.

A meu TDD é que nem aprender a programar, você só aprende realmente praticando, mas se você não tiver os conceitos básicos não evolui!

H

Discordo, acho que os conceitos são importantes

Ai eu já concordo, acredito que lendo e colocando em prática você começara a ter o dominio do TDD

Eu aprendi sozinho! Assim que comecei a ler o livro do Kent comecei a colocar em prática os conceitos e como o livro é muito simples é rápido de ler e praticar.

A meu TDD é que nem aprender a programar, você só aprende realmente praticando, mas se você não tiver os conceitos básicos não evolui!

+1 em tudo. [=

X

YvGa:

Como eu sempre digo, TDD eh muito simples, se está complicado é porque os conceitos de responsabilidade, desacoplamento, coesão e as coisas mais básicas de orientação a objetos ainda não estão claras na sua cabeça.

Implementar TDD não é fácil, mas porque OO não é fácil, embora pareça a princípio.

Parodiando uma frase atribuida a Descartes: Conhecimento em Orientação a Objetos é a coisa mais bem distribuída entre os programadores, ninguém acha que precisa mais do que já tem.

Estude Orientação a Objetos, muito e um pouco de TDD que as coisas saem naturalmente.

Concordo. TDD vai fazer que você tenha uma proliferação de classes enxutas e isso é estranho, pois inicialmente estamos acostumados com classes com excesso de responsabilidade e altamente acopladas a outras classes. As vezes é o extremo, uma classe possui uma dezena de responsabilidades e a outra não faz absolutamente nada a não ser conter os dados (as chamadas classes anêmicas) que acarreta em uma arquitetura praticamente procedural, díficil de testar e evoluir!

M

A idéia é fazer o teste antes do código, da para fazer algo “parecido” que eu uso codificando, voce “usa” metodos que ainda nao existem nas classes e depois vai la e cria.

X

:?: Não entendi nada :?:

Seriam métodos Stubs?

R

:?: Não entendi nada :?:

Seriam métodos Stubs?
Eu entendi hehehe, eu faço isso as vezes também.

Ao desenvolver a lógica de um método, percebo que fica melhor se eu criar uma outra classe, com um método nela, pra deixar tudo mais organizado.

Só que ao invés de criar a classe, eu continuo escrevendo meu método como se a classe já estivesse criada, depois vou lá e crio ela de verdade :slight_smile:

X

:?: Não entendi nada :?:

Seriam métodos Stubs?
Eu entendi hehehe, eu faço isso as vezes também.

Ao desenvolver a lógica de um método, percebo que fica melhor se eu criar uma outra classe, com um método nela, pra deixar tudo mais organizado.

Só que ao invés de criar a classe, eu continuo escrevendo meu método como se a classe já estivesse criada, depois vou lá e crio ela de verdade :)

Ah! Sim! Raramente faço isso, mas é valido primeiro cria a implementação mais simples que funciona e depois refatora! Nesse caso o ideal é anotar a refatoração como um novo teste para posterior implementação. Assim a implementação da nova classe fica condicionada e protegida dentro desse novo teste.

H

x@ndy:
A sim, raramente faço isso, mas é valido primeiro cria a implementação mais simples que funciona e depois refatora! Nesse caso o ideal é anotar a refatoração como um novo teste para posterior implementação. Assim a implementação da nova classe fica condicionada e protegida dentro desse novo teste.
I mano, mas o TDD pega o contrário.

Primeiro consiga um vermelho.
Depois um verde (agora que entra o código do método)
Refatore.

X

Hebert Coelho:
x@ndy:
A sim, raramente faço isso, mas é valido primeiro cria a implementação mais simples que funciona e depois refatora! Nesse caso o ideal é anotar a refatoração como um novo teste para posterior implementação. Assim a implementação da nova classe fica condicionada e protegida dentro desse novo teste.
I mano, mas o TDD pega o contrário.

Primeiro consiga um vermelho.
Depois um verde (agora que entra o código do método)
Refatore.

Sim Hebert, isso é um complemento do que ele falou anteriormente. O que ele disse é q cria o método e então descobre que esse método pode ser uma classe, mas mesmo assim ele cria a implementação óbvia desse método! A implementação óbvia é justamente para o obter a barra verde (Acredito que a barra vermelha tenha sido obtido rodando o método sem qualquer código)

A

x@ndy:
Hebert Coelho:
x@ndy:
A sim, raramente faço isso, mas é valido primeiro cria a implementação mais simples que funciona e depois refatora! Nesse caso o ideal é anotar a refatoração como um novo teste para posterior implementação. Assim a implementação da nova classe fica condicionada e protegida dentro desse novo teste.
I mano, mas o TDD pega o contrário.

Primeiro consiga um vermelho.
Depois um verde (agora que entra o código do método)
Refatore.

Sim Hebert, isso é um complemento do que ele falou anteriormente. O que ele disse é q cria o método e então descobre que esse método pode ser uma classe, mas mesmo assim ele cria a implementação óbvia desse método! A implementação óbvia é justamente para o obter a barra verde (Acredito que a barra vermelha tenha sido obtido rodando o método sem qualquer código)

Ahmn… não .

No TDD, a idéia é a seguinte:

  1. Escreva o teste (sem nem sequer haver a implementação que atenda ao teste).
  2. Rode o teste (ele deve, obrigatoriamente, falhar - já que a implementação não existe).
  3. Escreva a implementação.
  4. Rode o teste.
  5. Se o teste estiver falhando, arrume a implementação.
  6. Uma vez que o teste estiver passando, refatore até atingir o nível “ótimo” da implementação (ou seja, uma implementação performática, concisa, fácil de ler, etc.)

[]'s

X

Alexandre Saudate:
x@ndy:
Hebert Coelho:
x@ndy:
A sim, raramente faço isso, mas é valido primeiro cria a implementação mais simples que funciona e depois refatora! Nesse caso o ideal é anotar a refatoração como um novo teste para posterior implementação. Assim a implementação da nova classe fica condicionada e protegida dentro desse novo teste.
I mano, mas o TDD pega o contrário.

Primeiro consiga um vermelho.
Depois um verde (agora que entra o código do método)
Refatore.

Sim Hebert, isso é um complemento do que ele falou anteriormente. O que ele disse é q cria o método e então descobre que esse método pode ser uma classe, mas mesmo assim ele cria a implementação óbvia desse método! A implementação óbvia é justamente para o obter a barra verde (Acredito que a barra vermelha tenha sido obtido rodando o método sem qualquer código)

Ahmn… não .

No TDD, a idéia é a seguinte:

  1. Escreva o teste (sem nem sequer haver a implementação que atenda ao teste).
  2. Rode o teste (ele deve, obrigatoriamente, falhar - já que a implementação não existe).
  3. Escreva a implementação.
  4. Rode o teste.
  5. Se o teste estiver falhando, arrume a implementação.
  6. Uma vez que o teste estiver passando, refatore até atingir o nível “ótimo” da implementação (ou seja, uma implementação performática, concisa, fácil de ler, etc.)

[]'s

Pessoal, isso foi um complemento ao que ele falou, Vou tentar explicar melhor!

Eu crio um teste para calcular a media de um conjunto de valores de uma classe chamada Preços, por exemplo, na qual eu espero que a media retornada a seja 10!

Entao eu implemento o método média na classe preço (na verdade não pq o eclipse faz isso para mim ;)) que me retorna 0 e rodo meu testes ele falha, barra vermelha. Blz!

Começo a fazer a a implementação mais simples possível e ai e me toco que o calculo é complexo que é melhor transformar a média em um classe! Só que eu não paro e implemento a nova classe pois tenho um barra vermelha, então eu anoto a refatoração futura como um novo teste e continuo implementando, pois tenho que ver a barra verde. Termino rodo o teste e obtenho a barra verde. Blz.

Pego aquele teste marcado como a refatoração e implemento o teste para a classe média. Faço o ciclo até obter a barrar verde!
Após a barra verde do teste para a classe Média refatoro Teste da media dos Preços para utilizar a classe média e não um valor fixo seguindo o ciclo de TDD!

M

:?: Não entendi nada :?:

Seriam métodos Stubs?
Eu entendi hehehe, eu faço isso as vezes também.

Ao desenvolver a lógica de um método, percebo que fica melhor se eu criar uma outra classe, com um método nela, pra deixar tudo mais organizado.

Só que ao invés de criar a classe, eu continuo escrevendo meu método como se a classe já estivesse criada, depois vou lá e crio ela de verdade :)

É isso mesmo, e com os Content Assist do Eclipse fica até mais facil fazer surgir uma classe depois de propriamente escrita.

Para mim isso é um TDD sem teste hehehe

X

:?: Não entendi nada :?:

Seriam métodos Stubs?
Eu entendi hehehe, eu faço isso as vezes também.

Ao desenvolver a lógica de um método, percebo que fica melhor se eu criar uma outra classe, com um método nela, pra deixar tudo mais organizado.

Só que ao invés de criar a classe, eu continuo escrevendo meu método como se a classe já estivesse criada, depois vou lá e crio ela de verdade :)

É isso mesmo, e com os Content Assist do Eclipse fica até mais facil fazer surgir uma classe depois de propriamente escrita.

Para mim isso é um TDD sem teste hehehe

Isso é uma má prática pois o teste primário se refere a outra lógica. A nova classe é uma consequência de uma refatoração e deve possuir testes próprios! Um exemplo é que ao criar uma nova classe não existem testes para as pré condições dos métodos dessas classes, então, digamos um método dessa nova classe que não pode receber um valor negativo não é testado podendo quebrar com a(s) invariante(s) da classe!

Y

Marky.Vasconcelos:

É isso mesmo, e com os Content Assist do Eclipse fica até mais facil fazer surgir uma classe depois de propriamente escrita.

Para mim isso é um TDD sem teste hehehe

Acho que esse eh um dos pontos mais fortes do TDD, o fato de voce usar uma classe antes mesmo dela existir porque faz voce entender o que deve fazer antes de ficar batendo cabeça implementando.

Eu tambem uso mesmo em pontos onde não é possível/viável (no momento) ter testes unitários.

N

von.juliano:
Você pode ler sobre os conceitos, mas não vai aprender a fazê-lo lendo livros.

Pratique muito, vá em dojos, code com pessoas que já tem prática. Quanto mais você praticar tdd, mais rápido vai dominá-la. Dojos são excelentes ambientes para tal. Você também pode fazer um curso, um instrutor pode te passar várias manhas, mas novamente, você precisa praticar muito.

Obrigado pelas indicações e tenho equilibrado a questão de aprender(qualquer coisa) conceitos através de livros e praticar realmente.

N

Com pair programming tive alguns avanços, mas infelizmente aqui na empresa não sempre tem alguém com mais experiência e tempo para ajudar.

D

Alexandre Saudate:
x@ndy:
Hebert Coelho:
x@ndy:
A sim, raramente faço isso, mas é valido primeiro cria a implementação mais simples que funciona e depois refatora! Nesse caso o ideal é anotar a refatoração como um novo teste para posterior implementação. Assim a implementação da nova classe fica condicionada e protegida dentro desse novo teste.
I mano, mas o TDD pega o contrário.

Primeiro consiga um vermelho.
Depois um verde (agora que entra o código do método)
Refatore.

Sim Hebert, isso é um complemento do que ele falou anteriormente. O que ele disse é q cria o método e então descobre que esse método pode ser uma classe, mas mesmo assim ele cria a implementação óbvia desse método! A implementação óbvia é justamente para o obter a barra verde (Acredito que a barra vermelha tenha sido obtido rodando o método sem qualquer código)

Ahmn… não .

No TDD, a idéia é a seguinte:

  1. Escreva o teste (sem nem sequer haver a implementação que atenda ao teste).
  2. Rode o teste (ele deve, obrigatoriamente, falhar - já que a implementação não existe).
  3. Escreva a implementação.
  4. Rode o teste.
  5. Se o teste estiver falhando, arrume a implementação.
  6. Uma vez que o teste estiver passando, refatore até atingir o nível “ótimo” da implementação (ou seja, uma implementação performática, concisa, fácil de ler, etc.)

[]'s

Não teria ai antes da etapa 3, uma etapa de escrever o mínimo de código possível para que o teste passe, nem que seja um return null? Ai sim, vc escreve o seu primeiro esboço de implementação e prossiga nas demais etapas?

Uma dúvida que tenho referente ao primeiro passo e que já vi sendo discutida fortemente na web, ao escrever um teste para um método que não existe, eu obtenho um compilation fail e não um test fail. Pelo menos usando o Visual Studio não dá nem pra sair desse ponto, no Eclipse acho que ele permite rodar forçando e ai dá a barrinha vermelha. Mas de qualquer forma é um compilation fail.

Bom, são coisas diferentes obviamente, mas para o TDD em essência não é importante que a lógica do teste falhe em vez do compilador reclamar?

R

Daniel_MV:
Não teria ai antes da etapa 3, uma etapa de escrever o mínimo de código possível para que o teste passe, nem que seja um return null? Ai sim, vc escreve o seu primeiro esboço de implementação e prossiga nas demais etapas?

Uma dúvida que tenho referente ao primeiro passo e que já vi sendo discutida fortemente na web, ao escrever um teste para um método que não existe, eu obtenho um compilation fail e não um test fail. Pelo menos usando o Visual Studio não dá nem pra sair desse ponto, no Eclipse acho que ele permite rodar forçando e ai dá a barrinha vermelha. Mas de qualquer forma é um compilation fail.

Bom, são coisas diferentes obviamente, mas para o TDD em essência não é importante que a lógica do teste falhe em vez do compilador reclamar?


Isso é um ponto muito polêmico, qual o tamanho do passo a dar?

O tal dos baby steps pra mim devem ser usados como guia. Se você só vai escrever uma implementação pra passar no teste que retorne 0, pra depois fazer um if pra 2 testes, e aí 3 ifs pra 3 testes, mas já sabe a solução que irá resolver o problema, não precisa ir fazendo passo a passo, isso só vai tirar a sua produtividade.

Pra mim a ideia dos baby steps é te ajudar em cenários que você não conhece bem, lá você consegue ir devagar, tendo feedback, e desenvolvendo a solução mais simples possível. Agora em algo que você já tem domínio, na minha opinião você já pode dar passos um pouco maiores.

X

Rodrigo Sasaki:
Daniel_MV:
Não teria ai antes da etapa 3, uma etapa de escrever o mínimo de código possível para que o teste passe, nem que seja um return null? Ai sim, vc escreve o seu primeiro esboço de implementação e prossiga nas demais etapas?

Uma dúvida que tenho referente ao primeiro passo e que já vi sendo discutida fortemente na web, ao escrever um teste para um método que não existe, eu obtenho um compilation fail e não um test fail. Pelo menos usando o Visual Studio não dá nem pra sair desse ponto, no Eclipse acho que ele permite rodar forçando e ai dá a barrinha vermelha. Mas de qualquer forma é um compilation fail.

Bom, são coisas diferentes obviamente, mas para o TDD em essência não é importante que a lógica do teste falhe em vez do compilador reclamar?


Isso é um ponto muito polêmico, qual o tamanho do passo a dar?

O tal dos baby steps pra mim devem ser usados como guia. Se você só vai escrever uma implementação pra passar no teste que retorne 0, pra depois fazer um if pra 2 testes, e aí 3 ifs pra 3 testes, mas já sabe a solução que irá resolver o problema, não precisa ir fazendo passo a passo, isso só vai tirar a sua produtividade.

Pra mim a ideia dos baby steps é te ajudar em cenários que você não conhece bem, lá você consegue ir devagar, tendo feedback, e desenvolvendo a solução mais simples possível. Agora em algo que você já tem domínio, na minha opinião você já pode dar passos um pouco maiores.

Exatamente isso.
Pessoalmente não considero como barra vermelha o código nem ter compilado. A meu ver a barra vermelha deve ser obtida através de um resultado inválido.
O tamanho dos passos dados acredito que dependa da confiança no que se está implementando. Se estou fazendo algo que considero complicado ou que a lógica não está bem esclarecida na minha cabeça vou devagar e faço a implementação mais óbvia possível para obter a barra verde (normalmente uma copia do código de teste para o resultado esperado). Com a barra verde refatoro para a solução normal removendo a duplicação. Caso eu já tenha confiança e tenha entendido bem o que devo fazer pulo direto para implementação normal!

A

É um bom ponto, de fato. Não sou nenhum especialista no assunto, mas acho que a idéia da compilação falhar seria “provar” (grandes aspas, aqui) que o método / classe / whatever não existe antes de começar. Mas acho que não existe resposta certa, pra isso.

[]'s

W

Com Java, usando alguma IDE, eu já escrevo a classe e evito esses compilation fail. Mas escrevendo testes pra código javascript, python, ruby, onde eu normalmente uso um simples editor de texto, isto faz mais sentido.

Uma coisa muito produtiva que eu vi recentemente foi o testacular, framework para testes do angularjs. Ele fica rodando o tempo todo, basta você salvar o código que ele já roda. Aí você deixa ele rodando em background num lado da tela, e na outra vai escrevendo código. É simples, mas eu achei fantástico. :smiley:

R

wagnerfrancisco:
Com Java, usando alguma IDE, eu já escrevo a classe e evito esses compilation fail. Mas escrevendo testes pra código javascript, python, ruby, onde eu normalmente uso um simples editor de texto, isto faz mais sentido.

Uma coisa muito produtiva que eu vi recentemente foi o testacular, framework para testes do angularjs. Ele fica rodando o tempo todo, basta você salvar o código que ele já roda. Aí você deixa ele rodando em background num lado da tela, e na outra vai escrevendo código. É simples, mas eu achei fantástico. :smiley:


O SBT faz isso também, é muito interessante ter os testes rodando continuamente assim, é uma facilidade a mais na hora de desenvolver :slight_smile:

O Maven não faz isso?

W

Rodrigo Sasaki:
wagnerfrancisco:
Com Java, usando alguma IDE, eu já escrevo a classe e evito esses compilation fail. Mas escrevendo testes pra código javascript, python, ruby, onde eu normalmente uso um simples editor de texto, isto faz mais sentido.

Uma coisa muito produtiva que eu vi recentemente foi o testacular, framework para testes do angularjs. Ele fica rodando o tempo todo, basta você salvar o código que ele já roda. Aí você deixa ele rodando em background num lado da tela, e na outra vai escrevendo código. É simples, mas eu achei fantástico. :smiley:


O SBT faz isso também, é muito interessante ter os testes rodando continuamente assim, é uma facilidade a mais na hora de desenvolver :slight_smile:

O Maven não faz isso?

Legal… não sei se o maven faz algo assim, sinceramente até hoje só sabia do testacular.

M

x@ndy:
Marky.Vasconcelos:

Para mim isso é um TDD sem teste hehehe

Isso é uma má prática pois o teste primário se refere a outra lógica. A nova classe é uma consequência de uma refatoração e deve possuir testes próprios! Um exemplo é que ao criar uma nova classe não existem testes para as pré condições dos métodos dessas classes, então, digamos um método dessa nova classe que não pode receber um valor negativo não é testado podendo quebrar com a(s) invariante(s) da classe!

E quem disse que tenho testes? :stuck_out_tongue:

Ainda não achei a maneira correta de testar comportamente de views através de iterações com usuario, e eu não digo estados de formulario, e sim de translate através do tempo baseado na força.

Sim, isso ajuda muito, acho que esse é o essencial, o teste em si é para garantir qualidade.

X
Marky.Vasconcelos:
E quem disse que tenho testes? :p

Ainda não achei a maneira correta de testar comportamente de views através de iterações com usuario, e eu não digo estados de formulario, e sim de translate através do tempo baseado na força.


Com certeza nem tudo dá para fazer com TDD, um outro exemplo é programação multithread!

Marky.Vasconcelos:
Marky.Vasconcelos:
Para mim isso é um TDD sem teste hehehe
Acho que esse eh um dos pontos mais fortes do TDD, o fato de voce usar uma classe antes mesmo dela existir porque faz voce entender o que deve fazer antes de ficar batendo cabeça implementando.

Eu tambem uso mesmo em pontos onde não é possível/viável (no momento) ter testes unitários.

Sim, isso ajuda muito, acho que esse é o essencial, o teste em si é para garantir qualidade.
Isso não é verdade! O teste é mais que isso! Ele serve para projetar a logica que vai ser implementada e de dar um feedback que tudo esta certo. Para isso a lógica é implementada no código do teste! Um exemplo simples é o teste de uma média! Esse teste é um diminuto do que é o teste representa em TDD! Ali eu manipulo a logica da média e vejo como ela deve ser antes mesmo implementar o método. Na linha 6 eu digo que o que eu espero como média de 2 números é a soma deles divido por 2. A implementação disso no método resultado é um reflexo do que foi planejado no teste. Esse teste com certeza não garante a qualidade pois posso fazer o método retornar 6 e o teste irá passar. No próprio livro do Kent Beck comenta sobre isso falando que implementou 6 testes para um problema e outra pessoa implementou 65! Como a idéia de testes em TDD é encontrar a solução para um problema ele não pode garantir que todos os problemas que possa ter com um objeto serão cobertos. Na verdade com os testes em TDD se "obtêm" qualidade e não se "garante" a qualidade!
@Test
  public void testaMedia(){
    int valor1 = 10;
    int valor2 = 2;
    
    int mediaExperada = (valor1  + valor2) / 2
    
    Class media = new Media(valor1, valor2);
    assertEquals(mediaExperada, media.resultado())
  }
Como o teste serve para projetar a lógica de alguma coisa ("Um meio para um fim, segundo Kent Beck") então se eu tenho conhecimento da lógica eu não preciso criar um teste para ela! O exemplo acima é ótimo para isso também! Para que criar um teste para media de 2 números? Como sei como fazer isso posso passar direto para implementação, mas isso não vai ser considerado TDD, mesmo que eu pense antes em como implementar!
M

Por isso que o teste deveria ser:

@Test
  public void testaMedia(){
    int valor1 = 10;
    int valor2 = 2;
    
    int mediaExperada1 = (valor1  + valor2) / 2

    int mediaExperada1 = (8  +  8) / 2
    
    Class media = new Media(valor1, valor2);
    assertEquals(mediaExperada1, media.resultado())
    assertEquals(mediaExperada2 new Media(8,8).resultado())
  }
X
Marky.Vasconcelos:
Por isso que o teste deveria ser:
@Test
  public void testaMedia(){
    int valor1 = 10;
    int valor2 = 2;
    
    int mediaExperada1 = (valor1  + valor2) / 2

    int mediaExperada1 = (8  +  8) / 2
    
    Class media = new Media(valor1, valor2);
    assertEquals(mediaExperada1, media.resultado())
    assertEquals(mediaExperada2 new Media(8,8).resultado())
  }
Na verdade não! O que você fez ali se chama Triangulação em TDD e serve para dirimir duvidas com relação a lógica implementada! Como a lógica ali é tão simples que nem seria necessário utilizar TDD para cria-la faz muito menos sentido ainda utilizar Triangulação. Kent Beck beck fala sobre isso em seu livro:
Kent Beck:
Eu uso Triangulação apenas quando estou realmente muito inseguro sobre a implementação correta!
O problema é que você ainda não entendeu o sentido do teste. O teste não serve apenas para validar a logica na qual pensamos ou garantir a qualidade. Se você usa para isso, o teste abaixo seria o suficiente:
@Test
  public void testaMedia(){
    assertEquals(6, new Media(10,2).resultado())
    assertEquals(4, new Media(8,8).resultado())
  }
Eu posso pensar na lógica e implementar esse teste e então criar a classe media e o método resultado segundo o ciclo de TDD, mas essa não a finalidade do teste e definitivamente não é TDD. O teste em TDD visa projetar a logica e garantir que ela está correta!
M

Ta…

@Test
  public void testaMedia(){
    assertEquals(6, new Media(10,2).resultado())
    assertEquals(4, new Media(8,8).resultado())
  }

Isso era o mesmo que escrevi aqui rapidamente.

Mas de qualquer forma, escrever esses dois testes ajudaria a não implementar o Media#resultado() a retornar 6 e fazer o teste passar.

Vou procurar sobre triangulação conforme voce indicou.

Mas o conceito do TDD não está nesse teste escrito, é faze-lo antes de ter as classes que são testadas. É voce usar o que não existe e cria-lo depois, e esse o conceito que uso desenvolvendo mesmo sem testes.

Eu não sou ninguém para falar de testes, eu não uso com Android pelos motivos que eu disse. E nem mesmo de TDD pois só o que sei foram palestras e conversando com outros devs que levam isso na pratica.

X

Marky.Vasconcelos:
Ta…

@Test
  public void testaMedia(){
    assertEquals(6, new Media(10,2).resultado())
    assertEquals(4, new Media(8,8).resultado())
  }

Isso era o mesmo que escrevi aqui rapidamente.

Mas de qualquer forma, escrever esses dois testes ajudaria a não implementar o Media#resultado() a retornar 6 e fazer o teste passar.

Vou procurar sobre triangulação conforme voce indicou.

Mas o conceito do TDD não está nesse teste escrito, é faze-lo antes de ter as classes que são testadas. É voce usar o que não existe e cria-lo depois, e esse o conceito que uso desenvolvendo mesmo sem testes.

Eu não sou ninguém para falar de testes, eu não uso com Android pelos motivos que eu disse. E nem mesmo de TDD pois só o que sei foram palestras e conversando com outros devs que levam isso na pratica.


Novamente, isso não é TDD! TDD não uma coisa simples, do tipo “Ah, construa um teste e depois implemente a lógica, seguindo os passos vermelho, verde refatore!”! Isso é uma coisa simplista, um resumo que o pessoal prega e acha que é TDD. O que você aprendeu como sendo TDD está errado e a culpa provavelmente não é sua pois todo munda acha que está usando TDD e não tem a menor ideia do que ele realmente seja. Digo isso pois apreendi TDD inicialmente em fóruns, blogs, etc. Quando comecei a colocar na pratica tive diversas dificuldades pois muitas vezes os testes eram complexos ou até mesmo impossíveis de serem implementados. Um outro erro que eu fazia era executar os testes em uma sequencia especifica. Só fui apreender o que realmente era TDD quando li o livro do Kent Beck! Sugiro a todos que leiam esse livro (e leiam inteiro) para entender o que é TDD!

Y

x@ndy:
Marky.Vasconcelos:
Ta…

@Test
  public void testaMedia(){
    assertEquals(6, new Media(10,2).resultado())
    assertEquals(4, new Media(8,8).resultado())
  }

Isso era o mesmo que escrevi aqui rapidamente.

Mas de qualquer forma, escrever esses dois testes ajudaria a não implementar o Media#resultado() a retornar 6 e fazer o teste passar.

Vou procurar sobre triangulação conforme voce indicou.

Mas o conceito do TDD não está nesse teste escrito, é faze-lo antes de ter as classes que são testadas. É voce usar o que não existe e cria-lo depois, e esse o conceito que uso desenvolvendo mesmo sem testes.

Eu não sou ninguém para falar de testes, eu não uso com Android pelos motivos que eu disse. E nem mesmo de TDD pois só o que sei foram palestras e conversando com outros devs que levam isso na pratica.


Novamente, isso não é TDD! TDD não uma coisa simples, do tipo “Ah, construa um teste e depois implemente a lógica, seguindo os passos vermelho, verde refatore!”! Isso é uma coisa simplista, um resumo que o pessoal prega e acha que é TDD. O que você aprendeu como sendo TDD está errado e a culpa provavelmente não é sua pois todo munda acha que está usando TDD e não tem a menor ideia do que ele realmente seja. Digo isso pois apreendi TDD inicialmente em fóruns, blogs, etc. Quando comecei a colocar na pratica tive diversas dificuldades pois muitas vezes os testes eram complexos ou até mesmo impossíveis de serem implementados. Um outro erro que eu fazia era executar os testes em uma sequencia especifica. Só fui apreender o que realmente era TDD quando li o livro do Kent Beck! Sugiro a todos que leiam esse livro (e leiam inteiro) para entender o que é TDD!

O TDD nao eh simplista, ele eh simples mesmo e, a não ser que eu não esteja entendendo, o Mark não está discordando de você.

Além de que eu concordo com ele quando ele diz que o conceito de TDD é usar o código antes dele existir. Essa é a premissa principal, que inclusive dá nome a técnica (test first) e é esse conceito que te permite implementar a lógica do ponto de vista de um usuário da classe que está sendo criada/alterada. De quebra você tem um teste que garante que o resultado do que voce implementou era aquilo que você esperava que fosse.

Pra quem nunca ouviu falar, triangulação é uma prática na qual você cria um teste (por exemplo que te diz que a media de 2 e 4 é 3, faz com que seu método retorne 3 (return 3; ) e depois cria outro teste para o mesmo método dizendo que a média de 2 e 6 é 4. A partir dai a implementação que existe retornando 3 não é suficiente e você precisa alterá-la para que os dois testes passem.

Depois você escreve outro para outra situação e vai cercando a implementação com as possibilidades que existirem. É muito útil, mas em casos simples você pode dar passos maiores.

Voltando ao conceito de TDD eu sempre repito o mesmo, ele eh muito simples, muito fácil. Se está complicado é porque você tem problemas no código que está sendo testado, não nos testes.

X
YvGa:
O TDD nao eh simplista, ele eh simples mesmo e, a não ser que eu não esteja entendendo, o Mark não está discordando de você.
Embora as premissas de TDD pareçam simples ela é uma das técnicas mais difíceis que já fiz tanto que no inicio é extremamente comum não segui-lo e, se você leu o livro do Kent Beck, vê que até para ele em alguns momentos a técnica não é fácil! E isso está relacionado a maneira como aprendemos a programar. No mesmo livro ele diz que TDD é extremamente natural para sua filha porque ele ensinou para ela a técnica enquanto a ensinava a programar.
YvGa:
Além de que eu concordo com ele quando ele diz que o conceito de TDD é usar o código antes dele existir. Essa é a premissa principal, que inclusive dá nome a técnica (test first) e é esse conceito que te permite implementar a lógica do ponto de vista de um usuário da classe que está sendo criada/alterada. De quebra você tem um teste que garante que o resultado do que voce implementou era aquilo que você esperava que fosse.
Esse o conceito está errado. A técnica não é usar o código antes de ele existir pois se você usa o código antes de ele existir então já tem o código na sua cabeça e sem tem na sua cabeça é só criar o método e coloca-lo dentro e, desse modo, tanto faz se você cria o método de teste antes ou depois pois você já projetou toda a lógica e o teste acaba só sendo uma forma de garantir que aquilo que você projetou está correto! Sendo assim a premissa inicial do colega é valida pois o teste só serve para garantir que o que foi feito esta certo e eu posso ter um TDD sem testes!

Isso é natural porque estamos condicionados a pensar assim pois fomos ensinados assim! Sempre nós projetamos na nossa cabeça e depois implementamos só que TDD não é isso pois nesse caso o desenvolvimento não está sendo dirigido pelo teste e sim pela forma que achamos que aquilo deve funcionar!

Embora isso até pareca correto (e em alguns momentos podemos usar isso com práticas TDD) este não é o cerne da finalidade do teste. A ideia é que o teste ajude no projeto da lógica e, nesse caso, a lógica não está na sua cabeça. Você não usa a lógica antes, você projeta a lógica a partir do teste. Para ilustrar isso vou usar o mesmo exemplo da média acima e vou partir do pressuposto que nunca calculei uma média antes. Na minha lista de teste eu adicionei o seguinte: Calcular a média de 2 numeros. Então o que faço primeiro é:
@Test
  public void testaMedia()
    int mediaExperada;
    assertEquals(mediaExperada, media.resultado());
  }
Ai eu penso, como calculo uma média (ou vou na wikipedia)? Eu lembro que uma media é a soma de um conjunto de números dividido pelo número de elementos da soma. Então eu faço:
@Test
  public void testaMedia(){
    int mediaExperada = Soma / numeroDeElemendoDaSoma;
    assertEquals(mediaExperada, media.resultado());
  }
Blz mas qual o número de elementos da soma? Bom nesse caso eu sei pelo que foi especificado na lista de teste que é dois então eu faço:
@Test
  public void testaMedia(){
    int soma = elemento1 + elemento2;
    int numeroDeElementos = 2;

    int mediaExperada = soma / numeroDeElemendoDaSoma;
    assertEquals(mediaExperada, media.resultado());
  }
Eu olho para o código e só falta declarar os elementos então:
@Test
  public void testaMedia(){
    int elemento1 = 10;
    int elemento2 = 12;

    int soma = elemento1 + elemento2;
    int numeroDeElementos = 2;

    int mediaExperada = soma / numeroDeElemendoDaSoma;
    assertEquals(mediaExperada, media.resultado());
  }
Esse foi um exemplo bem step by step do que é o "dirigido" por testes e que a finalidade fundamental do teste é ajudar ajudar a projetar a logica. Desse modo o teste também faz com que se obtenha feedback do que foi implementado está certo e por consequência o acaba ajudando a garantir a qualidade porém essas não são as principais finalidades dele!

Claro que se eu sei a lógica eu não preciso fazer tão passo a passo e posso ir direto para a última implementação, mas, nesse caso, só estou preocupado em obter o feedback positivo e em garantir a qualidade e, embora isso faça parte de TDD, eu estou usando somente o "Desenvolvimento" e o "Teste" porém fica faltando o faltando o "Dirigido" ai!

Buscar somente o feedback e garantir a qualidade ocorre muito durante a pratica de TDD pois muitas vezes sabe-se como implementar algo (em outras ocasiões você vai ter tanta confiança em algo que não vai nem se dar ao trabalho de implementar um teste) e, embora essas ações não sejam as principais finalidades do teste não é errado faze-lo pois TDD não é um contrato fixo que diz que você obrigado a projetar a lógica usando o teste.

YvGa:
Pra quem nunca ouviu falar, triangulação é uma prática na qual você cria um teste (por exemplo que te diz que a media de 2 e 4 é 3, faz com que seu método retorne 3 (return 3; ) e depois cria outro teste para o mesmo método dizendo que a média de 2 e 6 é 4. A partir dai a implementação que existe retornando 3 não é suficiente e você precisa alterá-la para que os dois testes passem.

Depois você escreve outro para outra situação e vai cercando a implementação com as possibilidades que existirem. É muito útil, mas em casos simples você pode dar passos maiores.


Isso está correto, mas ele não está relacionado ao número de passos e sim na confiança no que você projetou! Ele deve ser usado quando você tem duvidas sobre a logica que implementou (independente de ela ser simples ou complexa)! Se você tem dúvida sobre alguma coisa use triangulação.

YvGa:
Voltando ao conceito de TDD eu sempre repito o mesmo, ele eh muito simples, muito fácil. Se está complicado é porque você tem problemas no código que está sendo testado, não nos testes.
Isso soa estranho pois se você usa TDD da maneira correta não deveria ter problemas com o código testado pois projetou o código a partir do teste sendo assim o problema estaria no seu teste!

Pela experiência que tenho quando se está tendo problemas com os testes o problema com certeza está no código mas é por você não está usando TDD da maneira correta!

Isso não quer dizer que as coisas não vão ficar estranhas quando se está usando TDD da maneira correta, pelo contrário, mas nesses casos você esta projetando com ajuda do teste então tem feedback antes de implementar a classe ou método!
Nesse momento você vê começa a se questionar se seus testes representam fielmente o dominio da aplicação! Pega a lista de testes revê cada um dos testes já implementados e começa a criar testes alternativos de modo a criar um modelo mais fidedigno e isso é muito legal pois você acaba por criar novos testes e a descartar testes antigos o que leva a uma grande refatoração no sistema para um modelo mais rico!

M

Eu já disse, não uso “TDD” e os projetos de testes aqui estão fechados a meses.

Eu sigo a filosofia use-first/create-later sem testes, isso me ajuda a terminar macro features sem ter implementado toda logica necessaria.

E já que o que eu aprendi não é TDD, vou procurar para ver se existe um nome ou então criar um eu mesmo :wink:

Eu não vi diferença no exemplo da media do que eu fiz para o que voce postou, o TDD ajuda a projetar, mas você não vai precisar ir na wikipedia para fazer algo que já sabe. Nesse caso acredito que voce esteja seguindo a propria arquitetura que já esperava.

E o fato de criar a logica no teste já deixa uma armadilha, se voce copia-la para dentro do método que quer testar, claro que ela vai ser testada com sucesso, mas é por que o teste só compara valores e não a logica em si.

Voce não vai fazer um projeto sem saber qual é o destino (as vezes podem faltar definições, mas isso é culpa do projeto e vai refletir na aplicação).

Vou ler o livro do Kent Beck quando adquiri-lo.

X

Marky.Vasconcelos:

Eu não vi diferença no exemplo da media do que eu fiz para o que voce postou, o TDD ajuda a projetar, mas você não vai precisar ir na wikipedia para fazer algo que já sabe. Nesse caso acredito que voce esteja seguindo a propria arquitetura que já esperava.

Eu já falei sobre isso ai em cima:

Você pode definir o número de passo que vai dar em TDD, então no exemplo da média posso fazer exatamente como você falou até mesmo sem a triangulação, mas a finalidade do teste não é garantir a qualidade. A finalidade principal do teste é projetar e ter o feedback positivo, garantir a qualidade é uma consequência disso.

Marky.Vasconcelos:

E o fato de criar a logica no teste já deixa uma armadilha, se voce copia-la para dentro do método que quer testar, claro que ela vai ser testada com sucesso, mas é por que o teste só compara valores e não a logica em si.

A ideia não é fazer um copy/paste e sim e projetar e partir disso desenvolver a logica. Em TDD existe remover a duplicação então se você copia e cola depois tem que remover a duplicação e mesmo assim se existe duvida pode usar a triangulação. O use-first/create-later apresenta o mesmo problema pois você também pode fazer um copy/paste!

TDD também não é infalível, não é bala de prata, então você cometerá erros que não serão cobertos pela base de testes e as vezes até erros de lógica que os testes não pegaram

A

A próxima vez que alguém me perguntar a diferença entre um mock e um stub, vou entregar o link dessa mensagem… :wink:

S

Marky.Vasconcelos:
Eu já disse, não uso “TDD” e os projetos de testes aqui estão fechados a meses.

Eu sigo a filosofia use-first/create-later sem testes, isso me ajuda a terminar macro features sem ter implementado toda logica necessaria.

E já que o que eu aprendi não é TDD, vou procurar para ver se existe um nome ou então criar um eu mesmo :wink:

Isso que vc faz se chama Test First, que não é a mesma coisa que TDD apesar do muita gente acha.
O que o x@ndy está tentando demonstrar é como se usa o TDD sem cair num simples Test First, mas ele está sendo traído pelo exemplo que escolheu, que é trivial.

Faça o mesmo processo com algo mais complexo, como criar um builder para os Criteria do Hibernate, ou um builder para uma api de validação, ou um processo de negócio como a transferencia entre contas que considera o fee que o cliente paga e o tipo de cliente, ou algo que vc não saiba à priori como calcular seno usando BigDecimal em vez de double, ou calcula multiplicação de matrizes com multithread. Tem que ser algo desconhecido e com complexidade não trivial , pois senão não ha “desenvolvimento” envolvido e TDD precisa de “desenvolvimento” (Test Drive Development). É isso que o distingue do simples Test First.

Ai vc vai reconhecer os passos “baby steps” que o x@ndy está tentando exemplificar.

G

Eu acho que esse teste deveria ser:

@Test
  public void testaMedia(){
    int valor1 = 10;
    int valor2 = 2;
    
    Media media = new Media(valor1, valor2);
    assertEquals(6, media.resultado())
  }

Aquele primeiro teste está duplicando o código testado, não? Você há de concordar que a implementação do código de produção fatalmente vai ficar assim

int media = (valor1 + valor2) / 2 return media; Acaba não testando realmente porque sempre vai estar igual!

Na segunda maneira o resultado não está calculado dentro do método de teste, mas veio do meu conhecimento sobre o domínio, sobre como o sistema deve se comportar. O código de produção é que tem a “obrigação” de fazer o cálculo que for necessário para chegar ao resultado correto.

X

gomesrod:
x@ndy:

@Test
  public void testaMedia(){
    int valor1 = 10;
    int valor2 = 2;
    
    int mediaExperada = (valor1  + valor2) / 2
    
    Class media = new Media(valor1, valor2);
    assertEquals(mediaExperada, media.resultado())
  }

Eu acho que esse teste deveria ser:

@Test
  public void testaMedia(){
    int valor1 = 10;
    int valor2 = 2;
    
    Media media = new Media(valor1, valor2);
    assertEquals(6, media.resultado())
  }

Aquele primeiro teste está duplicando o código testado, não? Você há de concordar que a implementação do código de produção fatalmente vai ficar assim

int media = (valor1 + valor2) / 2 return media; Acaba não testando realmente porque sempre vai estar igual!

Na segunda maneira o resultado não está calculado dentro do método de teste, mas veio do meu conhecimento sobre o domínio, sobre como o sistema deve se comportar. O código de produção é que tem a “obrigação” de fazer o cálculo que for necessário para chegar ao resultado correto.


Faço minha as palavras do Sergio:

sergiotaborda:

O que o x@ndy está tentando demonstrar é como se usa o TDD sem cair num simples Test First, mas ele está sendo traído pelo exemplo que escolheu, que é trivial.

Faça o mesmo processo com algo mais complexo, como criar um builder para os Criteria do Hibernate, ou um builder para uma api de validação, ou um processo de negócio como a transferencia entre contas que considera o fee que o cliente paga e o tipo de cliente, ou algo que vc não saiba à priori como calcular seno usando BigDecimal em vez de double, ou calcula multiplicação de matrizes com multithread. Tem que ser algo desconhecido e com complexidade não trivial , pois senão não ha “desenvolvimento” envolvido e TDD precisa de “desenvolvimento” (Test Drive Development). É isso que o distingue do simples Test First.

Ai vc vai reconhecer os passos “baby steps” que o x@ndy está tentando exemplificar.


Esse exemplo realmente é simples e em todos os post coloquei que talvez nem fosse necessário criar um teste para isso! Foi somente para exemplificar que o teste serve para projetar a lógica e muitas vezes isso é composto até por mais de um teste mas você fala algo interessante:

Se você conhece o dominio e sabe como resolver o problema é só quer feedback positivo isto está certo (e na maioria das vezes vai ser assim) mas e caso você não soubesse como implementar isso, imagine uma logica muito mais complexa, como você faria? Outro problema da sua abordagem é que não existe diferença entre fazer o teste antes ou depois pois se você sabe como o sistema deve se comportar qual a diferença de implementar a lógica e depois testa-la de modo somente a saber que não cometemos nenhum erro?

Estou sem tempo agora, mas vou tentar fazer um exemplo mais complexo e postar no meu blog.

G

Mas mesmo que eu não saiba como implementar não tenho que saber de antemão qual o resultado esperado na operação? Calculado manualmente, ou por outra forma que confio que esteja correta?

Legal :!:

X

Não! Você vai descobrir o resultado implementando o teste! Isso é muito estranho mas essa é a grande sacada. A cada passo que você dá vai construindo a lógica que vai te levar ao resultado! Vejo muitos programadores fazerem “Teste de Mesa” para desenvolver uma lógica e o teste em TDD é muito parecido com isso. Ao invés de rascunhar algo no papel vou implementando no meu teste!

Claro que você não vai usar isso para tudo que for implementar pois, dependendo da confiança que você tem no que está fazendo, não é necessário. Já outras vezes é necessário um conjunto de testes simples para construir uma lógica mais complexa.

É complicado explicar bem como isso funciona! Eu mesmo só fui entender após ler o livro do Kent Beck, pois existem n conceitos envolvidos.

Digo que TDD é como orientação a objetos: muita gente acha que tem um sistema OO por que utiliza classes, polimorfismo e herança mas OOP é muito mais que isso assim como TDD é muito mais que crie o teste primeiro, barra vermelha, verde e refatore!

Y

Eu acho que se deve ter muito cuidado com essas afirmacoes. Eu entendi a duvida do gamesrod.

Talvez não seja essa a tua intenção, mas você passa a impressão de que usa os testes para descobrir a regra, o que nem de longe é verdade. A regra você sabe qual é, você precisa saber.

Para fazer uma transferência bancaria eu preciso saber que 10 reais sairão da conta A para a B, não é possível eu descobrir isso durante os testes. O uso dos testes me levará ao como não ao o quê.

Como eu disse, talvez não seja a sua intenção, mas é isso que está parecendo.

Particularmente, eu uso testes como o gamesrod citou, sei que a media de 10 e 2 é 5, essa é a regra e isso eu preciso saber de antemão, seja o quão complexo for, então espero que meu teste me retorne 5. O teste, além de servir pra ajudar a definir o meu modelo, além de garantir que as coisas continuarão funcionando como eu espero, ainda me serve como documentação, então ele precisa ser limpo, legível e a intenção dele tem que ser clara.

X

YvGa:
x@ndy:

Não! Você vai descobrir o resultado implementando o teste! Isso é muito estranho mas essa é a grande sacada. A cada passo que você dá vai construindo a lógica que vai te levar ao resultado! Vejo muitos programadores fazerem “Teste de Mesa” para desenvolver uma lógica e o teste em TDD é muito parecido com isso. Ao invés de rascunhar algo no papel vou implementando no meu teste!

Eu acho que se deve ter muito cuidado com essas afirmacoes. Eu entendi a duvida do gamesrod.

Talvez não seja essa a tua intenção, mas você passa a impressão de que usa os testes para descobrir a regra, o que nem de longe é verdade. A regra você sabe qual é, você precisa saber.

Para fazer uma transferência bancaria eu preciso saber que 10 reais sairão da conta A para a B, não é possível eu descobrir isso durante os testes. O uso dos testes me levará ao como não ao o quê.

Como eu disse, talvez não seja a sua intenção, mas é isso que está parecendo.

Particularmente, eu uso testes como o gamesrod citou, sei que a media de 10 e 2 é 5, essa é a regra e isso eu preciso saber de antemão, seja o quão complexo for, então espero que meu teste me retorne 5. O teste, além de servir pra ajudar a definir o meu modelo, além de garantir que as coisas continuarão funcionando como eu espero, ainda me serve como documentação, então ele precisa ser limpo, legível e a intenção dele tem que ser clara.

Pode ser que a palavra resultado não tenha sido bem empregada. Como resultado entenda-se o valor final da operação e não a regra de negócio. A finalidade do Teste é justamente testar a Regra! No caso da Média, qual seria a regra? Que a Média de 10 e 2 é 6? Como ficaria isso na minha lista de Teste? Qual a operação envolvida?

Para esse caso eu escreveria o seguinte na minha lista de teste: MEDIA = (X + Y)/2.

Note que o resultado da operação, nesse caso, não é importante (não que isso se aplique a tudo) e tanto faz se estou testando a media de 10 e 2 ou de 2232 e 4290. Sendo assim a asserção seria algo como assertEquals(mediaExperada, media.resultado()); Onde o mediaExperada seria o resultado do meu (X+Y) / 2.

Espero que tenha esclarecido.

S

YvGa:
x@ndy:

Não! Você vai descobrir o resultado implementando o teste! Isso é muito estranho mas essa é a grande sacada. A cada passo que você dá vai construindo a lógica que vai te levar ao resultado! Vejo muitos programadores fazerem “Teste de Mesa” para desenvolver uma lógica e o teste em TDD é muito parecido com isso. Ao invés de rascunhar algo no papel vou implementando no meu teste!

Eu acho que se deve ter muito cuidado com essas afirmacoes. Eu entendi a duvida do gamesrod.

Talvez não seja essa a tua intenção, mas você passa a impressão de que usa os testes para descobrir a regra, o que nem de longe é verdade. A regra você sabe qual é, você precisa saber.

Para fazer uma transferência bancaria eu preciso saber que 10 reais sairão da conta A para a B, não é possível eu descobrir isso durante os testes. O uso dos testes me levará ao como não ao o quê.

Como eu disse, talvez não seja a sua intenção, mas é isso que está parecendo.

Particularmente, eu uso testes como o gamesrod citou, sei que a media de 10 e 2 é 5, essa é a regra e isso eu preciso saber de antemão, seja o quão complexo for, então espero que meu teste me retorne 5. O teste, além de servir pra ajudar a definir o meu modelo, além de garantir que as coisas continuarão funcionando como eu espero, ainda me serve como documentação, então ele precisa ser limpo, legível e a intenção dele tem que ser clara.

É aqui que está o problema. O que vc está exemplificando é Test First. O que o x@ndy está falando é TDD. O TDD é sim para encontrar a regra no sentido que vc não sabe como nem o quê é o resultado. Vc sabe o que lhe especificaram, ou seja o behaviour. No caso seria “o sistema deve calcular a média”. Como disse o exemplo é trivial pq vc já sabe como se calcula uma média, portanto não ha desenvolvimento envolvido, só implementação. Entao vc estabelece balizas conhecidas nos seus testes como a média de 10 e 2 é 6 que irão provar que sua implmentação não está errada. Isto é Test First. O test serve como arcabouço do resultado. Em TDD o teste serve como exploração do resultado. Imagine q vc tem que integrar com o Twitter e não ha uma API em java para isso. Vc sabe a especificação “ler o timeline do twiter”, mas vc não sabe como nem o quê. Ou seja, que código eu preciso e como eu preciso organizá-lo. Ai vc investiga, começa sabendo que ha um URL para acessar, ai vc aprende o protocolo, etc… isso é apenas informaçao, mas com ela vc vai montando seu codigo. Usa um objeot URL para fazer a coneção e ler e processa o HTML na mão. Blz. funcioana, mas não é elegante e não faz tudo o que vc precisa. Ai vc começa a melhorar o código e o design. Tlv vc deixe de usar o URL e passa a usar o HTTPClient da apache, etc… vc está desenvolvendo a sua API de conversa com o twiter e está usando o junit - por exemplo - como cliente dessa api, e explorando se é fácil ou dificil de usar, de entender , etc… Não é uma mero teste de unidade é todo um ciclo de desenvolvimento em que o teste é o client da aplicação/api.

Eu sei que nuance não é trivial e é bem complexo de explicar , mas se vc tem uma especificação , tem um teste para ela e simplesmente procura uma implementação, então é Test First. Se vc tem a especificação, mas não procura apenas uma implementação, vc procura a melhor implementação, o melhor design, etc… isso é TDD. A diferença é o ultimo D = Development. Desenvolver significa que vc ainda não sabe o que precisa ou ainda não melhorou o suficiente para atender outros requisitos além da especificação ( como qualidade, boas práticas, simplicidade, DRY, etc…)

Criado 26 de fevereiro de 2013
Ultima resposta 7 de mar. de 2013
Respostas 49
Participantes 13