Estou tentando praticar o TDD, usando-o para desenvolver um simples como o Bit Vector. Por acaso, estou usando o Swift, mas essa é uma pergunta independente da linguagem.
My BitVector
é um struct
que armazena um único UInt64
e apresenta uma API sobre ele que permite tratá-lo como uma coleção. Os detalhes não importam muito, mas são bem simples. Os 57 bits altos são bits de armazenamento e os 6 bits inferiores são bits de "contagem", o que indica quantos bits de armazenamento realmente armazenam um valor contido.
Até agora, tenho um punhado de recursos muito simples:
- Um inicializador que constrói vetores de bits vazios
- Uma
count
propriedade do tipoInt
- Uma
isEmpty
propriedade do tipoBool
- Um operador de igualdade (
==
). Nota: este é um operador de igualdade de valor semelhante aoObject.equals()
Java, não um operador de igualdade de referência como==
no Java.
Estou enfrentando várias dependências cíclicas:
O teste de unidade que testa meu inicializador precisa verificar se o recém-construído
BitVector
. Isso pode ser feito de três maneiras:- Verifica
bv.count == 0
- Verifica
bv.isEmpty == true
- Verifique que
bv == knownEmptyBitVector
O método 1 depende
count
, o método 2 dependeisEmpty
(o qual dependecount
, então não faz sentido usá-lo), o método 3 depende==
. De qualquer forma, não consigo testar meu inicializador isoladamente.- Verifica
O teste
count
precisa operar com algo que inevitavelmente testa meus inicializadoresA implementação de se
isEmpty
baseia emcount
A implementação de
==
dependecount
.
Consegui resolver parcialmente esse problema, introduzindo uma API privada que constrói a BitVector
partir de um padrão de bits existente (como a UInt64
). Isso me permitiu inicializar valores sem testar nenhum outro inicializador, para que eu pudesse "arrancar a correia" no meu caminho.
Para que meus testes de unidade sejam realmente testes de unidade, eu me vejo fazendo um monte de hacks, o que complica substancialmente meu código de teste e teste.
Como exatamente você contorna esses tipos de problemas?
fonte
BitVector
é um tamanho de unidade perfeitamente adequado para testes de unidade e resolve imediatamente seus problemas de que os membros públicosBitVector
precisam um do outro para fazer testes significativos.Respostas:
Você está preocupado demais com os detalhes da implementação.
Não importa que, na sua implementação atual ,
isEmpty
dependacount
(ou de qualquer outro relacionamento que você possa ter): tudo com o que você deve se preocupar é com a interface pública. Por exemplo, você pode ter três testes:count == 0
.isEmpty == true
Todos esses são testes válidos e se tornam especialmente importantes se você decidir refatorar os internos de sua classe para que
isEmpty
tenha uma implementação diferente da qual não dependecount
- desde que todos os seus testes ainda passem, você sabe que não regrediu qualquer coisa.Coisas semelhantes se aplicam a seus outros pontos - lembre-se de testar a interface pública, não sua implementação interna. Você pode achar o TDD útil aqui, pois você escreveria os testes necessários
isEmpty
antes de escrever qualquer implementação para ele.fonte
Você revisa seu pensamento sobre o que é um "teste de unidade".
Um objeto que gerencia dados mutáveis na memória é fundamentalmente uma máquina de estado. Portanto, qualquer caso de uso valioso invoca, no mínimo, um método para colocar informações no objeto e invoca um método para ler uma cópia das informações do objeto. Nos casos de uso interessantes, você também invocará métodos adicionais que alteram a estrutura de dados.
Na prática, isso geralmente parece
ou
A terminologia do "teste de unidade" - bem, ele tem uma longa história de não ser muito bom.
Kent escreveu a primeira versão do SUnit em 1994 , o porto para JUnit foi em 1998, o primeiro rascunho do livro TDD foi no início de 2002. A confusão demorou muito tempo para se espalhar.
A idéia principal desses testes (mais precisamente chamados de "testes de programador" ou "testes de desenvolvedor") é que os testes são isolados um do outro. Os testes não compartilham nenhuma estrutura de dados mutáveis, para que possam ser executados simultaneamente. Não há preocupações de que os testes sejam executados em uma ordem específica para medir corretamente a solução.
O principal caso de uso desses testes é que eles são executados pelo programador entre as edições em seu próprio código-fonte. Se você estiver executando o protocolo de refatoração verde vermelho, um vermelho inesperado sempre indica uma falha em sua última edição; você reverte essa alteração, verifique se os testes são VERDES e tente novamente. Não há muita vantagem em tentar investir em um design em que todo e qualquer bug possível seja capturado por apenas um teste.
Obviamente, uma mesclagem introduz uma falha e, em seguida, descobrir que a falha não é mais trivial. Existem várias etapas que você pode executar para garantir que as falhas sejam fáceis de localizar. Vejo
fonte
Em geral (mesmo que não esteja usando o TDD), você deve se esforçar para escrever os testes o máximo possível, fingindo não saber como é implementado.
Se você está realmente fazendo TDD, esse já deve ser o caso. Seus testes são uma especificação executável do programa.
A aparência do gráfico de chamada abaixo dos testes é irrelevante, desde que os próprios testes sejam sensatos e bem mantidos.
Acho que seu problema é sua compreensão do TDD.
Seu problema, na minha opinião, é que você está "misturando" suas personas de TDD. Suas personas "teste", "código" e "refatorar" operam de forma completamente independente uma da outra, idealmente. Em particular, suas personas de codificação e refatoração não têm obrigações para com os testes, exceto para fazê-las / mantê-las funcionando em verde.
Claro, em princípio, seria melhor se todos os testes fossem ortogonais e independentes um do outro. Mas isso não é uma preocupação de suas outras duas pessoas TDD, e definitivamente não é um requisito rígido estrito ou mesmo necessariamente realista de seus testes. Basicamente: não descarte seus sentimentos de senso comum sobre a qualidade do código para tentar atender a um requisito que ninguém está pedindo a você.
fonte