Qual é o valor de escrever testes de unidade extras ao refazer uma função maior em funções menores?

8

Se eu tiver uma função complexa de unidade testada :

def do_everything():
    # turn twizzles
    # push buttons
    # move mountain

E eu o fatorizo ​​novamente em algumas unidades menores:

def do_everything():
    turn_twizzles()
    push_buttons()
    move_mountain()

def turn_twizzles():
    # turn twizzles

def push_buttons():
    # push buttons

def move_mountain():
    # move mountain

Estou perdendo meu tempo escrevendo testes de unidade extras para essas unidades menores?

Adam Terrey
fonte

Respostas:

15

Eu suponho que você já tem testes de unidade que cobrem o comportamento de do_everything()? Se você quebrou turn_twizzles()etc. como métodos privados, não alterou nenhum comportamento externo para não precisar alterar nenhum teste.

Se, no entanto, turn_twizzles()for tornado público, você introduziu uma nova funcionalidade (conforme observado de fora da classe), portanto, seria valioso testar isso.

JacquesB
fonte
2
Não tenho certeza por que esta resposta foi reduzida. É curto, direto ao ponto e 100% pontual em seus conselhos.
David Arno
Esta é uma resposta muito clara, obrigado. Eu acho que a questão (crédito a @Samuel por mencionar isso) é a questão do tempo ou não, a interface pública mudou.
23817 Adam Terrey
Voto negativo, porque isso não está completo. Mesmo que as novas funções não fizessem parte de uma API pública, escrever testes pode ser muito útil. Diga que um teste para do_everything () falha: onde está o erro? Se você tiver testes para as três subfunções, será bem mais fácil encontrá-lo. Esse é um benefício de escrever os testes e deve ser mencionado aqui.
Marstato #
1
@ marstato: Geralmente é considerado uma má idéia unittest métodos privados, uma vez que associa os testes aos detalhes da implementação.
JacquesB
@JaxquesB Isso geralmente não é uma coisa ruim. Você poderia dizer que algo mais preciso do que um teste de integração usual está vinculado aos detalhes da implementação. Mas você escreve esses testes de qualquer maneira porque eles ajudam a rastrear bugs, não porque eles ajudam a provar a funcionalidade correta. O modificador de acesso é sempre subjetivo. Uma privatepalavra-chave em uma linguagem de programação é apenas uma das muitas maneiras de restringir o acesso a um pedaço de código.
Marstato #
12

Depende. Para ser mais preciso, depende de

  • a complexidade da função original (se for muito complexa, o teste de cada parte será recompensado)
  • a complexidade das funções menores (se forem partes complexas por si só, testá-las individualmente resultará em testes mais detalhados e detecção mais precisa das causas raiz em caso de defeito)
  • os testes de unidade existentes (se eles já produzem cobertura suficiente para todas essas "partes", provavelmente vale menos a pena escrever testes individuais)
  • se você deseja manter essas funções menores "detalhes de implementação" das funções originais, ou não (no primeiro caso, escrever testes de unidade para as funções menores se tornaria contraproducente para esse objetivo).

Especialmente quando essas "funções menores" não são tão triviais como no seu exemplo, mas têm uma lista mais ou menos complexa de parâmetros de entrada, pode ser muito difícil produzir testes de unidade suficientes para sua função original para garantir que as funções menores sejam testadas com todas as combinações de entradas "interessantes". Isso seria um sinal claro para escrever testes de unidade específicos também para as funções menores.

Portanto, não há um "sim" ou "não" claro para essa pergunta; é uma troca que você deve decidir por caso.

Doc Brown
fonte
6

Se turn_twizzles,, push_buttonse move_mountainsão públicos e chamados por outro código, acho importante refatorar seus testes para testar essas funções individualmente.

Infelizmente, após a sua refactor você tem um problema: para teste de unidade do_everythingque você precisa para ser capaz de zombar turn_twizzles, push_buttonse move_mountain. Escrever testes do_everythingsem zombar das dependências será um teste de integração - não necessariamente uma coisa ruim, dependendo do seu plano de teste, mas não haverá muitos benefícios porque você já está testando as três funções menores individualmente. Pode ser o momento certo para você reprojetar esse componente e colaborar com outros objetos para realizar todo o trabalho do_everything.

Se turn_twizzles,, push_buttonse move_mountainnão forem chamados externamente, eles deverão ser marcados como particulares, e eu não recomendaria testá-los separadamente de do_everything. Isso ocorre porque, do ponto de vista de fora, do_everythingseria a menor unidade (porque as outras são inacessíveis). Veja também esta resposta sobre como dividir métodos usando métodos privados.

Samuel
fonte
4
Tenho downvoted isso como, " para teste de unidade do_everythingque você precisa para ser capaz de zombar turn_twizzles, push_buttonse move_mountain... " depende de uma definição absurdo de "teste de unidade".
David Arno
1
@ David, para ser justo, Samuel reconhece isso na resposta. Tipo de.
GnP
4

Não. Os testes de unidade extras são mais precisos. Se move_mountainfalhar, um único teste falhará que diz muito especificamente o que deu errado.

Essa precisão reduz o tempo de depuração, o que é valioso. Além disso, como o teste é mais focado, deve ser mais rápido executar do que testar a mesma funcionalidade através da função completa, fornecendo feedback mais rápido, o que é valioso.

Telastyn
fonte