É considerado 'má prática' verificar o conteúdo / codificação do arquivo em testes unitários?

84

Um pouco de contexto: hoje, tive de atualizar alguns códigos SQL fornecidos por outro colega meu e, como é um script bastante grande, ele é armazenado como um arquivo separado (que é lido e executado no tempo de execução). Ao fazer isso, eu acidentalmente reintroduzi dois bugs que tivemos alguns meses atrás, a saber:

  • Por qualquer motivo, o arquivo ASCII foi codificado em UTF-16 (o colega me enviou o arquivo por e-mail, o que pode ter causado isso).
  • O script estava sem as instruções SET iniciais (necessárias devido a algumas coisas do driver na produção, mas não em uma instalação limpa localmente).

Depois de depurar isso por cerca de uma hora (novamente), decidi escrever alguns testes unitários para garantir que isso nunca mais aconteceria (e inclua uma maneira rápida de corrigi-lo na mensagem de asserção para fornecer uma correção fácil para futuros desenvolvedores).

No entanto, quando eu empurrei esse código, outro colega (que também é o líder da nossa equipe) veio até mim e disse que eu não deveria fazer essas coisas de novo porque:

"These things don't belong in unit tests"

"Unit tests should only be used to check the flow of your code"

Estou bastante conflituosa agora, pois ainda acho que o que estou fazendo não está errado, já que esse bug não seria reintroduzido no futuro, no entanto, esse colega trabalha como um veterano e, no final do dia, fica para decidir com o que gastamos nosso tempo. O que devo fazer? Estou errado por fazer isso dessa maneira? Isso é considerado uma prática ruim?

    
por Paradoxis 30.10.2017 / 19:57
fonte

12 respostas

156

O mais provável é que os testes que você escreveu estejam mais próximos dos testes de integração ou de regressão do que os testes de unidade. Embora a linha possa ser muito imprecisa e algumas vezes passar para o pedantismo sobre o que é ou não um teste de unidade, eu voltaria ao seu colega e perguntaria onde os testes que você escreveu devem ser, pois agregam valor garantindo a correção do código. / p>

Eu não me concentraria muito no que é ou não é um teste de unidade e percebo que mesmo que seja um teste de integração, ainda pode haver valor no teste.

    
por 30.10.2017 / 20:07
fonte
36

Tecnicamente, não é um teste de unidade e mais uma etapa de validação. A abordagem correta realmente depende do que seu fluxo de trabalho precisa ser. O líder da sua equipe está correto sobre qual é o objetivo dos testes de unidade. Meu sentimento é que este é um caso de usar a ferramenta errada para um trabalho que ainda precisa ser feito. Então comece com isso:

What's the problem I'm trying to solve?

Pela descrição, você precisa validar se os scripts de banco de dados estão em conformidade com alguns padrões.

What tools/processes are available to solve the problem?

A qualidade do código-fonte é geralmente verificada pelas ferramentas análise estática . Se você não tiver uma ferramenta de análise estática para validar seu SQL, poderá criar uma ferramenta rápida e suja que executa a verificação em qualquer arquivo SQL transmitido para ele. Não faz mal verificar se existem ferramentas de análise estática que podem lidar com os problemas que você está falando.

Se você fizer parte de sua infraestrutura de criação, como incorporá-la ao Jenkins ou algo assim, ela poderá ser aplicada a todos os arquivos SQL do seu projeto.

Os testes da unidade apenas resolvem o problema do seu arquivo atual.

How do I communicate the need for the tool?

Isso é muito fácil, você fala com o líder da sua equipe. Ele pode trabalhar com o proprietário do produto e você para determinar o risco / recompensa de investir no ferramental. Se este é provavelmente um problema único, então o ferramental provavelmente seria um exagero. Se o ferramental para pegar os maiores problemas é fácil, pode valer a pena apenas para a verificação de sanidade.

Seu líder de equipe pode ter algumas ideias que você (ou eu) não consideramos, que podem resolver o problema de forma mais correta.

    
por 30.10.2017 / 20:10
fonte
19

É uma prática ruim chamar testes que acessam arquivos "Testes de Unidade".

He: "These things don't belong in unit tests"

You: "Makes sense, but I couldn't find a better place to put them. Where do they belong?"

Infelizmente, que tipos de testes existem e como eles são organizados são totalmente específicos da empresa. Então você precisa descobrir como sua empresa lida com esses testes.

Se você ainda não tem uma maneira de executar testes automatizados além dos Testes de Unidade, a abordagem pragmática é marcar os Testes de Unidade que não são Testes de Unidade com um prefixo, até que você tenha o suficiente para começar a descobrir Que tipo de testes você realmente tem / precisa. Depois disso, você pode começar a organizar.

    
por 31.10.2017 / 00:56
fonte
14

Michael Feathers diz isso em seu livro Working Effectively With Legacy Code:

In the industry, people often go back and forth about whether particular tests are unit tests. [...] I go back to the two qualities: Does the test run fast? Can it help us localize errors quickly?

Seu teste ajudará a localizar erros rapidamente e a funcionar rapidamente? Se sim, então faça! Se não, então não faça! É tão simples assim!

Dito isto, você está trabalhando em um ambiente com outras pessoas e precisa se dar bem com elas. Você pode ter que acabar fazendo isso do jeito dele, mesmo que você discorde em particular.

    
por 31.10.2017 / 02:45
fonte
10

Eu tenho escrito testes semelhantes, na ocasião, contra arquivos de código-fonte, arquivos de configuração e assim por diante. Eu não os chamaria de testes unitários porque (a) eles estão acessando o sistema de arquivos e podem não ser ultrarrápidos (b) Eu não ligo se eles são executados em cada check-in (ao contrário de todas as noites em um Servidor CI).

Você pode chamá-los de testes de integração; certamente, eles estão mais próximos dessa perspectiva do que os testes de unidade.

Meu próprio termo para eles é testes de recursos . IMHO, eles são inteiramente justificados se executados todas as noites em um servidor de CI: há um custo mínimo e, quando usado de forma criteriosa, adiciona valor claramente. Uma definição de criteriosamente : se o teste estiver verificando um problema que causou um problema (como a codificação mencionada).

    
por 31.10.2017 / 01:11
fonte
4

Um teste unitário tem tudo a ver com testar um método ou 'unidade' de código. Você está testando o menor grupo de lógica e código em seu software.

Mais tarde, quando você se unir a outras unidades, realizará o teste de integração.

Espero que o líder da sua equipe tenha incentivado sua iniciativa e tenha oferecido sugestões alternativas. Você definitivamente tem a ideia certa.

Seu SQL é um código como qualquer linguagem de geração inferior como C # ou Java e deve ser testado como tal. E a verificação e validação pertencem a todos os níveis de teste. Então codificação e instruções SET estão incluídas, mas não necessariamente testadas exclusivamente. Coisas gerais, como terminações de linha ou fechamento, geralmente podem ser usadas apenas com um gancho ou recurso do SCM.

A melhor prática é fazer testes de regressão para garantir que os erros passados não sejam reintroduzidos. Geralmente, os testes são criados ao lado de qualquer resolução do bug. Se esses bugs não forem cobertos por testes de regressão na unidade / integração ou no nível do sistema e, em seguida, forem reintroduzidos, será um problema de equipe, um problema de processo, não um problema individual.

A coisa é ... erros de sintaxe, instruções ausentes ou blocos lógicos dentro de uma 'unidade' normalmente não são testados. Você está testando as entradas e saídas da unidade em diferentes combinações, testando as muitas possibilidades que poderiam ser geradas.

Voltando às instruções SET ausentes - elas ajudam a informar as muitas possibilidades de entrada e saída para teste. Que teste você escreveria que falharia se você estivesse perdendo algum SET escolhido?

    
por 31.10.2017 / 06:07
fonte
3

Se você tiver arquivos que se tornem parte de seu produto, o conteúdo deles deverá estar correto. Não há motivo para você não confirmar isso. Por exemplo, se você precisar de seis imagens 1024x1024 em alguma pasta, então, por todos os meios, escreva um teste de unidade que verifique se você tem exatamente isso.

Mas você provavelmente não possui apenas os arquivos, você também tem algum código que lê os arquivos. Você poderia escrever um teste de unidade para esse código. No exemplo acima, a função para ler uma das seis imagens retorna uma imagem de 1024 x 1024 na memória (ou seja lá o que ela deveria produzir).

De qualquer forma, pode não ser um teste unitário, mas é um teste útil. E se você usar uma estrutura de teste de unidade que permita fazer um teste útil (que não seja um teste de unidade), por que não usar a estrutura de teste de unidade?

    
por 30.10.2017 / 21:00
fonte
2

Talvez eu esteja entendendo mal o seu problema, mas para mim isso parece um problema que não deve ser capturado por nenhum tipo de teste dedicado, mas simplesmente pelo sistema de controle de versão . Qualquer alteração em uma base de código deve ser revisada remendo por patch antes de ser confirmada. Uma maneira simples de fazer isso no git é adicionar as alterações com

git add -p

Para cada alteração em um arquivo de texto, o diretório de trabalho perguntará se você deseja mantê-lo. Isso permitiria ver, por exemplo, a exclusão dessas "declarações SET iniciais".

Caso a codificação de um arquivo inteiro fosse alterada, algo diferente aconteceria: o algoritmo não conseguiria diferenciar o arquivo antigo e o novo e, portanto, git add -p não adicionaria nada. Isso então seria visível no outro comando que eu faria antes de qualquer commit, a saber

git status

Aqui você veria o arquivo destacado em vermelho, indicando que há alterações . Investigar por que isso não aconteceu em git add -p tornaria o problema óbvio.

    
por 31.10.2017 / 20:58
fonte
1

Outro ângulo a considerar: como essas duas condições são requisitos para o seu programa ser executado, você não deveria incorporar a lógica próxima à lógica de execução? Quer dizer: você testa a existência de um arquivo antes de lê-lo e / ou validar seu conteúdo, certo? então como isso é diferente? Eu acho que desde que este é um recurso externo de código, ele deve ser validado em tempo de execução, antes de ser realmente usado. Resultado: aplicativo mais strong, sem necessidade de testes adicionais.

    
por 31.10.2017 / 12:56
fonte
1

Os testes são o mesmo código que qualquer outro e, se forem complexos o suficiente, também se beneficiarão de ... testes unitários. Parece mais simples adicionar essas verificações de pré-condição diretamente no teste.

A maioria dos testes é simples o suficiente para não exigir isso, mas se alguns são suficientemente complexos, não vejo nada de fundamentalmente errado com essas verificações de pré-condição. É claro que o teste também deve falhar sem eles, mas um bom teste de unidade também informa que qual unidade está falhando.

Um script que é usado como parte do teste e deve ter determinado conteúdo e codificação é provavelmente uma unidade. Pode ter muito mais código e lógica do que o resto do teste. Um teste com esse script não é o melhor design de todos os tempos e, se possível, deve ser refatorado em algo mais direto (a menos que seja um teste de integração).

    
por 01.11.2017 / 20:57
fonte
1

Em primeiro lugar - um dos propósitos dos testes é evitar que os problemas se repitam no seu código - então você absolutamente deve continuar escrevendo testes dessa natureza.

Em segundo lugar - nomear é difícil. Sim, estes não são claramente "testes de unidade", mas podem ser partes desejáveis e necessárias do processo de construção, porque protegem você de erros óbvios e porque dão feedback sobre erros mais cedo (especialmente se você não vê o erro). conseqüências em uma caixa de desenvolvimento).

Então, a questão realmente é (deve estar em seu contexto) mais sobre quando e como esses testes são executados do que o que eles são.

Eu usei esse tipo de teste extensivamente no passado - eles nos salvaram um monte de dor.

    
por 02.11.2017 / 12:48
fonte
1

Testes de unidade são sobre como executar uma unidade de código isoladamente para confirmar que ela está produzindo o resultado correto para a entrada correta. O isolamento deve fazer com que a unidade em teste e o próprio teste sejam repetíveis, ou seja, não dependam ou apresentem efeitos colaterais.

O SQL não é exatamente algo que possa ser testado isoladamente, portanto, qualquer teste de SQL não é exatamente um teste de unidade e, com exceção de instruções SELECT, é quase certo que tenha um efeito colateral. Podemos chamar isso de teste de integração em vez de teste de unidade.

É sempre sensato garantir que qualquer defeito que possa ser introduzido possa ser detectado o mais cedo possível no ciclo de desenvolvimento, e que seja benéfico fazê-lo de uma maneira que facilite a identificação da origem do defeito pode ser rapidamente corrigido.

Os testes em questão podem ser realocados mais apropriadamente do corpo de "testes de unidade" e colocados em outro lugar, mas não devem ser removidos se estiverem fazendo algo útil como proteção contra a possível introdução de um defeito que poderia levar horas para rastrear.

    
por 05.11.2017 / 19:32
fonte