TDD: como os testes obsoletos são eliminados?

5

Eu estava lendo algumas perguntas sobre o TDD aqui e descobri as minhas.

Eu entendo que o TDD é uma maneira de desenvolver ou capturar especificações / requisitos internos detalhados para o código no decorrer da escrita desse código.

Continuamos passo a passo e adicionamos proposições falsificáveis ao corpo da especificação na forma de testes. Mostramos que eles são falsos e depois escrevemos código para torná-los verdadeiros. Em seguida, refatorar, mantendo-os verdadeiros.

O problema é, como sabemos que todos os testes existentes estão permanecendo falseáveis (com relação à sua característica original)?

No decorrer da adição de algum novo elemento ao código por meio desse processo, suponha que alguns testes possam se tornar facilmente desatualizados no seguinte sentido: esses testes foram inicialmente associados a alguma alteração específica e, se essa alteração for agora revertida no código linha de base atual, talvez eles ainda passem. O que quer que esteja fazendo com que eles passem agora não é aquele recurso original que os impediu de passar.

Esses testes / especificações parecem lixo, o que aumenta a base de especificações sem qualquer substância. Ou ainda há valor em um teste que não é falso se a alteração do código original que o tornou verdadeiro for revertida, e não é óbvio que outro código é alterado para a base atual o tornaria falso ?

Existe algum processo de TDD para identificar esses testes? E eles são então removidos ou reescritos ou o que?

Ou, alternativamente, isso é totalmente prevenido de alguma forma?

    
por Kaz 29.07.2017 / 00:59
fonte

5 respostas

4

Uma das duas coisas está errada aqui.

Você realmente não seguiu o TDD

Se você seguir TDD, escreva um teste com falha e, em seguida, escreva o código para fazer o teste passar. Se você remover o código que o faz passar, então seu teste deve ter quebrado. Talvez você não tenha realmente seguido TDD e, portanto, construiu um teste de auto-passagem.

Seus testes verificam a falta de um problema em vez do sucesso

Testes de unidade não devem ser projetados para testar problemas. Eles devem ser concebidos como uma declaração de fato, que deve ser mantida. Por exemplo:

@Test
public void tableIsSortedAlphabetically() {
    Table t = new Table();
    t.addRow("Hello");
    t.addRow("World");
    t.addRow("Apple");
    assertEquals("Apple", t.getRow(0));
}

Observe como isso é formulado. Estamos testando que algo é classificado de uma maneira particular. Se o teste for projetado dessa maneira e for bem implementado, não há como remover o código que classifica uma tabela em ordem alfabética sem que este teste falhe.

Aqui está um teste que ainda passaria se o código em teste fosse removido.

@Test
public void userCanBeCreated() {
    User user = new User();
    user.setFirstName("Johnny");
    user.setLastName("Appleseed");

    try {
        user.save();
    }
    catch (Exception e) {
        fail(e);
    }
}

Se a implementação de user.save() foi alterada para não fazer nada, esse teste ainda passaria porque o teste não verifica se o comportamento está correto, mas apenas testa se ele não falha.

    
por 29.07.2017 / 02:55
fonte
3

The problem is, how do we know that all the existing tests are staying falsifiable (with regard to their original feature)?

Uma resposta é tornar os testes imutáveis

O padrão básico do TDD é o seguinte: você implementa um teste, vê a falha, atualiza o código de produção, vê-o passar. Desde que o teste permaneça inalterado a partir deste ponto, você pode ter certeza de que a implementação atual continua satisfazendo essa restrição.

Those tests/specifications seem like garbage which adds bulk to the specification base without any substance. Or is there still value in a test which doesn't go false if the original code change which made it true is reverted

Sim, porque o teste em si ainda é documentação da especificação. Um bom teste normalmente não força uma implementação específica - se fosse esse o caso, a refatoração não funcionaria. Em vez disso, o teste apenas restringe o conjunto de implementações possíveis àquelas que produzem um resultado específico.

Is there some TDD process to identify these tests?

Não realmente. Existem alguns protocolos que você pode aplicar para tentar identificar testes que não estão mais restringindo nada - teste de mutação, por exemplo.

And are they then removed or rewritten or what?

Se a especificação foi alterada, você pode retirar um teste. Se a especificação estiver inalterada, mas você perdeu a confiança no teste, introduza um novo teste, estabeleça confiança nele e retire o antigo.

    
por 29.07.2017 / 13:21
fonte
1

Os testes são direcionados ao comportamento. Não linhas de código.

A cobertura de código é boa, mas se eu conseguir o que quero sem código, tudo soa bem para mim.

O que me perturba é a ideia do teste não ser falsificável. Você não deveria ter o teste se não fosse falso. Mas se você adicionar uma linha de código que faz o teste 2 passar e também faz o teste 1 passar que costumava ser passado apenas por causa de outro código, então é hora de esse outro código, agora inútil, ser excluído. Mas mesmo sem eliminá-lo, o teste ainda é falsificável. Você só precisa quebrar uma linha diferente para codificar.

Um teste pode saber qual método ele chama ao testar, mas não sabe onde o comportamento exibido pelo método é codificado. Então, como eu poderia insistir que há um problema com um teste que vai falso quando deveria, que é quando o comportamento quebra, só porque onde o comportamento é codificado mudou?

Agora, tudo o que foi dito, se você não puder ver o teste e o código e descobrir onde o comportamento em teste está codificado, terá problemas maiores.

Agora, isso não está dizendo que os testes nunca precisam morrer. Você deve alterar seus testes também.

is this entirely prevented somehow?

Apenas revise seus testes regularmente. Você deveria estar fazendo isso de qualquer maneira. Você vê um que você não tem certeza de como poderia ser falsificado parar tudo e ir quebrar algo para torná-lo falso. É assim que você testa o teste.

    
por 29.07.2017 / 05:08
fonte
0

Você não deve pensar em testes como testando linhas de código específicas . Em vez disso, um teste verifica se um aspecto de um requisito é atendido pelo sistema ou subsistema de uma forma ou de outra.

Um teste não estará obsoleto desde que o requisito esteja presente, mesmo que o código que originalmente cumpriu o requisito seja completamente reescrito ou substituído.

Desde que um teste realmente toque o sistema, ele tem o potencial de ficar vermelho, se alguém fizer uma alteração no código. Quer dizer, se alguém apagou todo o código, certamente todos os seus testes falharão.

    
por 29.07.2017 / 13:52
fonte
0

Um dos benefícios do TDD é que você é forçado a escrever código contra abstrações. Então, quando você reconhece alguma lógica que pode ser movida para fora da unidade atual por trás da abstração e passada na unidade como dependência. Você acaba com várias abstrações das quais sua unidade depende.

Com abstrações você não precisa de uma implementação existente, mas apenas implemente uma nova. Onde mais tarde você pode reconhecer classes não referenciadas por ninguém, a maior parte do IDE fornece esse recurso e as remove com testes correspondentes.

    
por 31.07.2017 / 20:49
fonte

Tags