A metodologia TDD pode ser aplicada de cima para baixo?

13

Não estou claro como o TDD, a metodologia, lida com o seguinte caso. Suponha que eu queira implementar o algoritmo mergesort, em Python. Eu começo escrevendo

assert mergesort([]) === []

e o teste falha com

NameError: o nome 'mergesort' não está definido

Eu adiciono

def mergesort(a):
    return []

e meu teste passa. Em seguida eu adiciono

assert mergesort[5] == 5

e meu teste falha com

AssertionError

com que passo

def mergesort(a):
    if not a:
        return []
    else:
        return a

Em seguida, adiciono

assert mergesort([10, 30, 20]) == [10, 20, 30]

e agora tenho que tentar fazer isso passar. Eu "conheço" o algoritmo mergesort, então escrevo:

def mergesort(a):
    if not a:
        return []
    else:
        left, right = a[:len(a)//2], a[len(a)//2:]
        return merge(mergesort(left)), mergesort(right))

E isso falha com

NameError: o nome 'mesclar' não está definido

Agora, aqui está a pergunta. Como posso fugir e começar a implementar mergeusando o TDD? Parece que não posso porque tenho esse teste "pendurado" não realizado e com falha mergesort, que não será aprovado até que mergeseja concluído! Se esse teste persistir, nunca poderei realmente executar o TDD porque não serei "verde" durante a construção das iterações do TDD merge.

Parece que estou preso aos três cenários feios a seguir e gostaria de saber (1) qual deles a comunidade TDD prefere ou (2) há outra abordagem que estou perdendo? Eu assisti várias orientações do tio Bob TDD e não me lembro de ter visto um caso como esse antes!

Aqui estão os 3 casos:

  1. Implemente a mesclagem em um diretório diferente com um conjunto de testes diferente.
  2. Não se preocupe em ser ecológico ao desenvolver a função auxiliar, apenas acompanhe manualmente os testes que realmente deseja passar.
  3. Comente (GASP!) Ou exclua as linhas mergesortnessa chamada merge; depois mergede trabalhar, coloque-os de volta.

Tudo isso me parece bobo (ou estou vendo isso errado?). Alguém sabe a abordagem preferida?

Ray Toal
fonte
2
Parte do objetivo do TDD é ajudá-lo a criar um design de software. Parte desse processo de design é descobrir o que é necessário para produzir o resultado desejado. No caso de mergesort, como já é um algoritmo muito bem definido, esse processo de descoberta não é necessário e torna-se uma questão de mapear o que você já sabe ser o design para uma série de testes de unidade. Presumivelmente, o seu teste de nível superior afirma que seu método em teste aceita uma coleção não triados e retorna um ordenado um ...
Robert Harvey
1
... Os testes de unidade subsequentes iriam se aprofundar gradualmente na mecânica real de a mergesort. Se você está procurando a maneira "certa" de fazer isso, não há outra, além de ser preciso sobre o mapeamento do mergesortalgoritmo para uma série de testes de unidade; ou seja, eles devem refletir o que mergesortrealmente faz.
Robert Harvey
4
O design não cresce apenas a partir de testes de unidade; se você espera que um mergesortdesign saia naturalmente do refator vermelho-verde, isso não acontecerá, a menos que você guie o processo com base no seu conhecimento existente mergesort.
Robert Harvey
1
No TDD mergedeve ser inventado apenas no estágio de "refatoração". Se você perceber que esse mergemétodo pode ser introduzido para passar no teste, mergesortprimeiro faça seus testes sem mergemétodo. Em seguida, refatorar sua implementação, introduzindo o mergemétodo
Fabio

Respostas:

13

Aqui estão algumas maneiras alternativas de analisar suas opções. Mas primeiro, as regras do TDD, do tio Bob, com ênfase por mim:

  1. Você não tem permissão para escrever nenhum código de produção, a menos que seja aprovado no teste de unidade.
  2. Você não tem permissão para escrever mais testes de unidade que o suficiente para falhar; e falhas de compilação são falhas.
  3. Você não tem permissão para escrever mais código de produção que o suficiente para passar no único teste de unidade com falha.

Portanto, uma maneira de ler a regra número 3 é que você precisa da mergefunção para passar no teste, para poder implementá-la - mas apenas na sua forma mais básica.

Ou, alternativamente, você começa escrevendo a operação de mesclagem on-line e depois a refatora em uma função depois de fazer o teste funcionar.

Outra interpretação é que você está escrevendo um mergesort, sabe que precisará de uma mergeoperação (ou seja, não é YAGNI, que é o que a regra "suficiente" tenta reduzir). Portanto, você deve ter iniciado os testes para a mesclagem e só então prosseguir para os testes para a classificação geral.

kdgregory
fonte
Essas são realmente boas observações. Eu havia pensado no fatorial e fatorial anteriormente, mas, como mergeé surpreendentemente bagunçado, inteligente (e útil como um autônomo), a ideia de fazê-lo como uma função separada fazia mais sentido. No entanto, o estilo de fazê-lo em linha na sua forma básica e depois fatorá-lo no estágio do chapéu azul realmente parece estar certo e muito o que eu estava procurando.
precisa
@ RayToal - Na verdade, eu me inclino para a abordagem de testar completamente a mergeoperação antes de fazer a classificação (bem como testes separados da partitionoperação). Eu acho que os benefícios reivindicados pelo design emergente vêm do trabalho lento em direção a um objetivo conhecido. No caso do mergesort, não acho que o objetivo seja classificar em geral (porque você acabará com a classificação por bolhas). Você conhece as operações básicas e trabalha nessas operações; o tipo é principalmente uma reflexão tardia.
precisa saber é o seguinte
1
Há uma quarta opção. Passe a mergefunção mergesorte zombe de seu comportamento. Então volte e implemente o mergeteste primeiro. Os delegados são impressionantes ™.
precisa
@RubberDuck A zombaria de uma parte integrante do domínio principal pode causar alguns problemas, mais especificamente quando você executa o programa e a função de simulação e mesclagem diferem nos mínimos detalhes. Uma abordagem como essa deve ser deixada para os casos em que você trabalha com recursos externos, como de onde vem a lista para classificação.
cllamach