Os testes de integração (banco de dados) são ruins?

120

Algumas pessoas afirmam que os testes de integração são ruins e errados - tudo deve ser testado em unidade, o que significa que você precisa zombar de dependências; uma opção que, por várias razões, nem sempre gosto.

Acho que, em alguns casos, um teste de unidade simplesmente não prova nada.

Vamos tomar a seguinte implementação (trivial, ingênua) do repositório (em PHP) como exemplo:

class ProductRepository
{
    private $db;

    public function __construct(ConnectionInterface $db) {
        $this->db = $db;
    }

    public function findByKeyword($keyword) {
        // this might have a query builder, keyword processing, etc. - this is
        // a totally naive example just to illustrate the DB dependency, mkay?

        return $this->db->fetch("SELECT * FROM products p"
            . " WHERE p.name LIKE :keyword", ['keyword' => $keyword]);
    }
}

Digamos que eu queira provar em um teste que esse repositório pode realmente encontrar produtos que correspondem a várias palavras-chave.

Sem testes de integração com um objeto de conexão real, como posso saber que isso realmente está gerando consultas reais - e que essas consultas realmente fazem o que eu acho que elas fazem?

Se eu tiver que zombar do objeto de conexão em um teste de unidade, só posso provar coisas como "ele gera a consulta esperada" - mas isso não significa que ele realmente funcionará ... ou seja, talvez esteja gerando a consulta Eu esperava, mas talvez essa consulta não faça o que eu acho que faz.

Em outras palavras, sinto que um teste que faz afirmações sobre a consulta gerada é essencialmente sem valor, porque está testando como o findByKeyword()método foi implementado , mas isso não prova que ele realmente funciona .

Esse problema não se limita aos repositórios ou à integração do banco de dados - parece aplicar-se em muitos casos, onde fazer afirmações sobre o uso de um mock (teste duplo) prova apenas como as coisas são implementadas, não se elas vão realmente funciona.

Como você lida com situações como essas?

Os testes de integração são realmente "ruins" em um caso como este?

Entendo que é melhor testar uma coisa e também entendo por que o teste de integração leva a uma infinidade de caminhos de código, os quais não podem ser testados - mas no caso de um serviço (como um repositório) cujo único objetivo é para interagir com outro componente, como você pode realmente testar alguma coisa sem o teste de integração?

mindplay.dk
fonte
5
Leia agitar.com/downloads/TheWayOfTestivus.pdf , especialmente na página 6 "O teste é mais importante que a unidade".
Doc Brown
2
@ user61852 diz "ingênuo" na descrição, sim?
mindplay.dk
4
Como seu colega de trabalho estaria absolutamente certo de que seu banco de dados zombado se comporta como a coisa real?
Thorbjørn Ravn Andersen
12
Você está tentando ser realista. Seu colega de trabalho está tentando aderir às regras. Sempre escreva testes que produzem valor . Não perca tempo escrevendo testes que não podem ser mantidos e não escreva testes que não executam um dos seguintes procedimentos: aumente a probabilidade de seu código estar correto ou force você a escrever um código mais sustentável.
Jpmc26
3
@ mindplay.dk: a frase-chave desse parágrafo é "Mas não fique preso a nenhum dogma. Escreva o teste que precisa ser escrito." Seu colega de trabalho parece estar preso a um dogma. E você não precisa de alguém explicando qual é o teste que precisa ser escrito em seu exemplo - você já sabe disso.É bastante óbvio que, para testar se o banco de dados entende a consulta, é necessário executá-la no banco de dados real - nenhum mock pode lhe dizer isso.
Doc Brown

Respostas:

129

Seu colega de trabalho está certo de que tudo o que pode ser testado em unidade deve ser testado em unidade, e você está certo de que os testes de unidade o levarão apenas até agora e não mais, principalmente ao escrever wrappers simples em serviços externos complexos.

Uma maneira comum de pensar sobre o teste é como uma pirâmide de teste . É um conceito frequentemente conectado ao Agile, e muitos já escreveram sobre ele, incluindo Martin Fowler (que o atribui a Mike Cohn em Sucesso com o Agile ), Alistair Scott e o Blog de testes do Google .

        /\                           --------------
       /  \        UI / End-to-End    \          /
      /----\                           \--------/
     /      \     Integration/System    \      /
    /--------\                           \----/
   /          \          Unit             \  /
  --------------                           \/
  Pyramid (good)                   Ice cream cone (bad)

A noção é que testes de unidade resilientes e de execução rápida são a base do processo de teste - deve haver testes de unidade mais focados que testes de sistema / integração e mais testes de sistema / integração que testes de ponta a ponta. À medida que você se aproxima do topo, os testes tendem a levar mais tempo / recursos para serem executados, tendem a estar mais sujeitos a fragilidade e falhas e são menos específicos na identificação de qual sistema ou arquivo está quebrado ; naturalmente, é preferível evitar ser "pesado demais".

Nesse ponto, os testes de integração não são ruins , mas uma forte dependência deles pode indicar que você não projetou seus componentes individuais para serem fáceis de testar. Lembre-se, o objetivo aqui é testar o desempenho da sua unidade de acordo com as especificações, enquanto envolve um mínimo de outros sistemas que podem ser quebrados : você pode tentar um banco de dados em memória (que eu considero um teste fácil de testar duas vezes ao lado de zombarias) ) para testes pesados ​​de casos extremos, por exemplo, e depois escreva alguns testes de integração com o mecanismo de banco de dados real para estabelecer que os casos principais funcionem quando o sistema é montado.


Como observação lateral, você mencionou que as simulações que você escreve simplesmente testam como algo é implementado, não se ele funciona . Isso é um antipadrão: um teste que é um espelho perfeito de sua implementação não está realmente testando nada. Em vez disso, teste se todas as classes ou métodos se comportam de acordo com suas próprias especificações , em qualquer nível de abstração ou realismo que exija.

Jeff Bowman
fonte
13
+1 em "Um teste que é um espelho perfeito de sua implementação não está realmente testando nada". Muito comum. Eu chamo isso de Antipadrão da Doppelganger .
Dodgethesteamroller
6
Uma escola contrária de controle de qualidade de software, o movimento de testes orientado ao contexto , é em parte dedicada à disputa de que existem regras gerais úteis como a Pirâmide de Testes. Em particular, os textos seminais do movimento dão muitos exemplos em que os testes de integração são muito mais valiosos do que outros tipos de testes (porque eles testam o sistema em contexto, como um sistema ) ...
dodgethesteamroller
7
... consequentemente, Fowler et al., ao argumentar que menos esforço deve ser gasto em testes de integração e testes de aceitação do usuário, porque são muito difíceis de escrever de maneira robusta e sustentável, estão apenas fornecendo uma desculpa ex post facto para o porquê eles não descobriram como testar bem em níveis mais altos.
Dodgethesteamroller
1
@dodgethesteamroller Discussões detalhadas de uma "escola contrária" como essa provavelmente são mais adequadas à sua própria resposta. Pessoalmente, acho que o Blog de testes do Google faz um bom trabalho descrevendo as virtudes de testes automáticos rápidos e de escopo estreito, além de testes do sistema em contexto. Caso você não ache claro, listo a pirâmide de teste aqui como um modelo ou ponto de partida útil, não como uma desculpa para parar de pensar como engenheiro.
11136 Jeff Bowman #
1
Apresentação altamente recomendada sobre a hierarquia e a proporção de unittests para testes de integração: vimeo.com/80533536 Muito bem explicado.
Szalski #
88

Um de meus colegas de trabalho sustenta que os testes de integração são ruins e errados - tudo deve ser testado em unidade,

É como dizer que os antibióticos são ruins - tudo deve ser curado com vitaminas.

Os testes de unidade não podem capturar tudo - eles apenas testam como um componente funciona em um ambiente controlado . Os testes de integração verificam que tudo funciona juntos , o que é mais difícil de fazer, mas mais significativo no final.

Um processo de teste bom e abrangente usa os dois tipos de testes - testes de unidade para verificar regras de negócios e outras coisas que podem ser testadas independentemente e testes de integração para garantir que tudo funcione em conjunto.

Sem testes de integração com um objeto de conexão real, como posso saber que isso realmente está gerando consultas reais - e que essas consultas realmente fazem o que eu acho que elas fazem?

Você poderia testá-lo no nível do banco de dados . Execute a consulta com vários parâmetros e veja se obtém os resultados esperados. Concedido significa copiar / colar quaisquer alterações novamente no código "true". mas não permitem que você testar o independente consulta de quaisquer outras dependências.

D Stanley
fonte
Você não estaria testando se o banco de dados contém ou não determinados dados?
Tulains Córdova
Possivelmente - mas você também pode estar testando se seus filtros, junções complexas etc. funcionam. A consulta de exemplo provavelmente não é a melhor candidata a "testes de unidade", mas uma com junções e / ou agregações complexas.
D # # Stanley #
Sim - o exemplo que usei, como apontado, é trivial; um verdadeiro repositório pode ter todos os tipos de pesquisa complexa e opções de classificação, por exemplo, usando um construtor de consulta, etc.
mindplay.dk
2
Boa resposta, mas gostaria de acrescentar que o banco de dados deve estar na memória, para garantir que os testes de unidade sejam rápidos.
BЈовић
3
@ Bћовић: Infelizmente, isso nem sempre é possível, pois infelizmente não existem dois DBs compatíveis por aí e nem todos eles funcionam na memória. Há também problemas de licenciamento para bancos de dados comerciais (que você pode não ter a licença para executá-lo em qualquer máquina), ...
Matthieu M.
17

Os testes de unidade não detectam todos os defeitos. Mas eles são mais baratos de configurar e (re) executam em comparação com outros tipos de testes. Os testes de unidade são justificados pela combinação de valor moderado e custo baixo a moderado.

Aqui está uma tabela mostrando as taxas de detecção de defeitos para diferentes tipos de teste.

insira a descrição da imagem aqui

fonte: p.470 em Code Complete 2 por McConnell

Nick Alexeev
fonte
5
Esses dados foram coletados em 1986 . Isso foi há trinta anos . Os testes de unidade em 1986 não eram o que são hoje. Eu ficaria cético em relação a esses dados. Para não mencionar, os testes de unidade detectam o bug antes que ele seja comprometido , então é duvidoso que eles sejam relatados.
precisa
3
@RubberDuck Este gráfico é de um livro de 2006 e é baseado em dados de 1986, 1996, 2002 (se você observar com atenção). Não examinei os protocolos de coleta de dados nas fontes, não sei dizer quando eles começaram a rastrear um defeito e como ele foi relatado. Este gráfico pode estar um pouco desatualizado? Poderia. Em dezembro passado, eu estava em um seminário, e o instrutor mencionou que os testes de integração encontram mais erros do que os testes de unidade (por um fator de 2, iirc). Este gráfico diz que eles são praticamente os mesmos.
21816 Nick Elliothe
13

Não, eles não são ruins. Felizmente, é preciso ter testes de unidade e integração. Eles são usados ​​e executados em diferentes estágios do ciclo de desenvolvimento.

Testes unitários

Os testes de unidade devem ser executados no servidor de compilação e localmente, após a compilação do código. Se algum teste de unidade falhar, deve-se falhar na compilação ou não confirmar a atualização do código até que os testes sejam corrigidos. A razão pela qual queremos testes de unidade isolados é que queremos que o servidor de compilação possa executar todos os testes sem todas as dependências. Em seguida, poderíamos executar a construção sem todas as dependências complexas necessárias e ter muitos testes que são executados muito rapidamente.

Portanto, para um banco de dados, deve-se ter algo como:

IRespository

List<Product> GetProducts<String Size, String Color);

Agora, a implementação real do IRepository irá para o banco de dados para obter os produtos, mas para testes de unidade, pode-se zombar do IRepository com um falso para executar todos os testes conforme necessário, sem um banco de dados actaul, pois podemos simular todo tipo de lista de produtos sendo retornado da instância simulada e teste qualquer lógica de negócios com os dados simulados.

Testes de integração

Testes de integração geralmente são testes de cruzamento de limites. Queremos executar esses testes no servidor de implantação (o ambiente real), na caixa de proteção ou mesmo localmente (apontado para a caixa de proteção). Eles não são executados no servidor de construção. Depois que o software foi implantado no ambiente, normalmente eles seriam executados como atividade pós-implantação. Eles podem ser automatizados através de utilitários de linha de comando. Por exemplo, podemos executar o nUnit na linha de comando se categorizarmos todo o teste de integração que queremos chamar. Na verdade, eles chamam o repositório real com a chamada de banco de dados real. Esses tipos de testes ajudam com:

  • Prontidão de estabilidade na saúde ambiental
  • Testando a coisa real

Às vezes, esses testes são mais difíceis de executar, pois também precisamos instalar e / ou desmontar. Considere adicionar um produto. Provavelmente, queremos adicionar o produto, consultá-lo para ver se ele foi adicionado e, depois que terminarmos, remova-o. Não queremos adicionar centenas ou milhares de produtos de "integração", portanto, é necessária uma configuração adicional.

Os testes de integração podem revelar-se bastante valiosos para validar um ambiente e garantir que a coisa real funcione.

Um deve ter os dois.

  • Execute os testes de unidade para cada compilação.
  • Execute os testes de integração para cada implantação.
Jon Raynor
fonte
Eu recomendaria executar testes de integração para cada build, em vez de precisar confirmar e enviar por push. Depende de quanto tempo eles levam, mas também é uma boa ideia mantê-los rápidos por vários motivos.
Artbristol
@ArtBristol - Normalmente, nosso servidor de compilação não possui a dependência total do ambiente configurada, portanto, não podemos executar nossos testes de integração lá. Mas se alguém puder executar os testes de integração lá, faça isso. Temos uma sandbox de implantação configurada após a compilação que usamos para testar a integração para verificar a implantação. Mas cada situação é diferente.
Jon Raynor
11

Testes de integração de banco de dados não são ruins. Ainda mais, eles são necessários.

Você provavelmente tem seu aplicativo dividido em camadas, e isso é uma coisa boa. Você pode testar cada camada isoladamente zombando das camadas vizinhas, e isso também é bom. Mas não importa quantas camadas de abstração você crie, em algum momento deve haver uma camada que faça o trabalho sujo - na verdade, converse com o banco de dados. A menos que você o teste, você não o faz . Se você testar a camada n zombando da camada n-1, estará avaliando a suposição de que a camada n funciona sob a condição de que a camada n-1 funcione. Para que isso funcione, você deve, de alguma forma, provar que a camada 0 funciona.

Embora em teoria você possa unidade de banco de dados de teste, analisando e interpretando o SQL gerado, é muito mais fácil e confiável criar banco de dados de teste rapidamente e conversar com ele.

Conclusão

Qual é a confiança obtida com os testes unitários das camadas Repositório Abstrato , Ethereal Objeto-Relacional-Mapeador , Registro Ativo Genérico e Persistência Teórica , quando no final o SQL gerado contém erro de sintaxe?

el.pescado
fonte
Eu estava pensando em adicionar uma resposta semelhante à sua, mas você disse isso melhor! Na minha experiência, ter alguns testes na camada que obtém e armazena dados me salvou muito.
precisa saber é o seguinte
Testes de integração de banco de dados são ruins, no entanto. Você tem um banco de dados disponível na sua linha ci / cd? Isso me parece bastante complexo. É muito mais fácil zombar do material do banco de dados e criar uma camada de abstração para usá-lo. Não é apenas uma solução muito mais elegante, é a mais rápida possível. Os testes de unidade precisam ser rápidos. Testar seu banco de dados reduz a velocidade de suas unittests significativamente para um nível que não é aceitável. Os unittests não devem levar mais de 10 minutos para serem feitos, mesmo quando você tiver milhares deles.
David David
@ David Você tem um banco de dados disponível na sua linha de ci / cd? Claro, esse é um recurso bastante padrão . BTW, não estou defendendo testes de integração em vez de testes de unidade - estou defendendo testes de integração em conjunto com testes de unidade. Testes de unidade rápidos são essenciais, mas os bancos de dados são complexos demais para depender de testes de unidade com interações simuladas.
el.pescado
@ el.pescado Eu tenho que discordar. Se a comunicação do banco de dados estiver por trás de uma camada de abstração, é realmente fácil zombar. Você pode apenas decidir qual objeto retornar. Além disso, o fato de algo ser padrão não o torna uma coisa boa.
David David
@ David Acho que depende de como você aborda o banco de dados. É o detalhe da implementação ou parte vital do sistema ? (Eu me inclino para o último) . Se você tratar o banco de dados como um armazenamento estúpido de dados, sim, poderá fazer isso sem testes de integração. No entanto, se houver alguma lógica no banco de dados - restrições, gatilhos, chaves estrangeiras, transações ou sua camada de dados usa SQL personalizado em vez de métodos ORM simples, acho que apenas os testes de unidade não serão suficientes.
el.pescado
6

Você precisa dos dois.

No seu exemplo, se você estava testando um banco de dados em uma determinada condição, quando o findByKeywordmétodo é executado, você obtém os dados de volta e espera que este seja um bom teste de integração.

Em qualquer outro código que esteja usando esse findByKeywordmétodo, você deseja controlar o que está sendo alimentado no teste, para que você possa retornar nulos ou as palavras certas para o seu teste ou o que quer que seja, para simular a dependência do banco de dados, para saber exatamente o que será o seu teste. receber (e você perde a sobrecarga de se conectar a um banco de dados e garantir que os dados contidos estejam corretos)

Froome
fonte
6

O autor do artigo do blog ao qual você se refere se preocupa principalmente com a complexidade potencial que pode surgir dos testes integrados (embora seja escrito de uma maneira muito opinativa e categórica). No entanto, testes integrados não são necessariamente ruins e alguns são realmente mais úteis que testes de unidade puros. Realmente depende do contexto do seu aplicativo e do que você está tentando testar.

Atualmente, muitos aplicativos simplesmente não funcionariam se o servidor de banco de dados fosse desativado. Pelo menos, pense no contexto do recurso que você está tentando testar.

Por um lado, se o que você está tentando testar não depende, ou pode ser feito para não depender, do banco de dados, escreva seu teste de tal maneira que ele nem tente usar o banco de dados (basta fornecer dados simulados, conforme necessário). Por exemplo, se você está tentando testar alguma lógica de autenticação ao veicular uma página da web (por exemplo), provavelmente é uma boa coisa desanexá-la completamente do banco de dados (supondo que você não confie no banco de dados para autenticação ou que você pode zombar razoavelmente facilmente).

Por outro lado, se é um recurso que depende diretamente do seu banco de dados e que não funcionaria em um ambiente real, se o banco de dados não estivesse disponível, zombaria do que o banco de dados faz no seu código de cliente do banco de dados (ou seja, a camada que usa esse DB) não faz necessariamente sentido.

Por exemplo, se você sabe que seu aplicativo dependerá de um banco de dados (e possivelmente de um sistema de banco de dados específico), zombar do comportamento do banco de dados por causa disso geralmente será uma perda de tempo. Mecanismos de banco de dados (especialmente RDBMS) são sistemas complexos. Algumas linhas de SQL podem realmente executar muito trabalho, o que seria difícil de simular (na verdade, se sua consulta SQL tiver algumas linhas, é provável que você precise de muito mais linhas de Java / PHP / C # / Python código para produzir o mesmo resultado internamente): duplicar a lógica que você já implementou no banco de dados não faz sentido e verificar se o código de teste se tornaria um problema em si.

Eu não trataria isso necessariamente como um problema de teste de unidade versus teste integrado , mas sim olhar para o escopo do que está sendo testado. Os problemas gerais dos testes de unidade e integração permanecem: você precisa de um conjunto razoavelmente realista de dados e casos de teste, mas algo que também seja suficientemente pequeno para que os testes sejam executados rapidamente.

A hora de redefinir o banco de dados e preencher novamente com os dados de teste é um aspecto a considerar; você geralmente avaliaria isso contra o tempo que leva para escrever esse código falso (que você também precisaria manter também).

Outro ponto a considerar é o grau de dependência que seu aplicativo possui do banco de dados.

  • Se seu aplicativo simplesmente seguir um modelo CRUD, no qual você tem uma camada de abstração que permite alternar entre qualquer RDBMS pelos meios simples de uma configuração, é provável que você possa trabalhar com um sistema simulado com bastante facilidade (possivelmente desfocando a linha entre a unidade e o teste integrado usando um RDBMS na memória).
  • Se seu aplicativo usa uma lógica mais complexa, algo que seria específico de um servidor SQL, MySQL, PostgreSQL (por exemplo), geralmente faria mais sentido ter um teste que usasse esse sistema específico.
Bruno
fonte
"Atualmente, muitos aplicativos simplesmente não funcionariam se o servidor de banco de dados fosse desativado" - esse é o ponto realmente importante!
El.pescado 4/11/15
Boa explicação dos limites de zombarias complexas, como usar outra linguagem para zombar de SQL. Quando o código de teste é complicado o suficiente para parecer que precisa ser testado, é um cheiro de controle de qualidade.
Dodgethesteamroller
1

Você está certo ao pensar em um teste de unidade como incompleto. A incompletude está na interface do banco de dados sendo zombada. As expectativas ou afirmações ingênuas de tais simulações são incompletas.

Para completá-lo, você teria que poupar tempo e recursos suficientes para escrever ou integrar um mecanismo de regras SQL que garantisse que a instrução SQL emitida pelo sujeito em teste resultaria nas operações esperadas.

No entanto, a alternativa / companheira frequentemente esquecida e um tanto cara à zombaria é a "virtualização" .

Você pode gerar uma instância de banco de dados temporária, na memória, mas "real" para testar uma única função? sim ? lá, você tem um teste melhor, aquele que verifica os dados reais salvos e recuperados.

Agora, pode-se dizer, você transformou um teste de unidade em um teste de integração. Existem várias visualizações sobre onde desenhar a linha para classificar entre testes de unidade e testes de integração. IMHO, "unidade" é uma definição arbitrária e deve atender às suas necessidades.

SD
fonte
1
este parece apenas repetir pontos feitos e explicado em esta resposta antes que foi publicado há algumas horas
mosquito
0

Unit Testse Integration Testssão ortogonais entre si. Eles oferecem uma visão diferente sobre o aplicativo que você está construindo. Geralmente você quer os dois . Mas o momento é diferente, quando você deseja que tipo de teste.

O mais frequentemente que você deseja Unit Tests. Os testes de unidade concentram-se em uma pequena parte do código que está sendo testado - o que exatamente é chamado de unité deixado para o leitor. Mas o objetivo é simples: obter feedback rápido de quando e onde seu código foi quebrado . Dito isto, deve ficar claro, que as chamadas para um banco de dados real não são válidas .

Por outro lado, existem coisas que só podem ser testadas em condições difíceis sem um banco de dados. Talvez exista uma condição de corrida no seu código e uma chamada para um banco de dados lance uma violação de uma unique constraintque só poderia ser lançada se você realmente usar seu sistema. Mas esses tipos de testes são caros e você não pode (e não deseja) executá-los com a mesma frequência unit tests.

Thomas Junk
fonte
0

No mundo .Net, eu tenho o hábito de criar um projeto de teste e criar testes como um método de codificação / depuração / teste de ida e volta menos a interface do usuário. Esta é uma maneira eficiente de me desenvolver. Eu não estava tão interessado em executar todos os testes para cada build (porque diminui o fluxo do meu trabalho de desenvolvimento), mas entendo a utilidade disso para uma equipe maior. No entanto, você pode estabelecer que, antes de confirmar o código, todos os testes devem ser executados e aprovados (se levar mais tempo para os testes serem executados porque o banco de dados está realmente sendo atingido).

Zombar da camada de acesso a dados (DAO) e não atingir o banco de dados, não só não me permite codificar da maneira que eu gosto e me acostumei, mas perde uma grande parte da base de código real. Se você não está realmente testando a camada de acesso a dados e o banco de dados e apenas fingindo, e depois gastando muito tempo zombando das coisas, não consigo entender a utilidade dessa abordagem para realmente testar meu código. Estou testando um pedaço pequeno em vez de um pedaço maior com um teste. Entendo que minha abordagem pode ser mais parecida com um teste de integração, mas parece que o teste de unidade com a simulação é um desperdício de tempo redundante se você realmente escrever o teste de integração uma vez e primeiro. Também é uma boa maneira de desenvolver e depurar.

De fato, há algum tempo eu tenho conhecimento do TDD e do Behavior Driven Design (BDD) e pensando em maneiras de usá-lo, mas é difícil adicionar testes de unidade retroativamente. Talvez eu esteja errado, mas escrever um teste que cubra mais código de ponta a ponta com o banco de dados incluído, parece ser um teste de prioridade muito mais completo e com maior prioridade, que cobre mais código e é uma maneira mais eficiente de escrever testes.

Na verdade, acho que algo como o Behavior Driven Design (BDD), que tenta testar de ponta a ponta com a linguagem específica de domínio (DSL), deve ser o caminho a percorrer. Temos o SpecFlow no mundo .Net, mas ele começou como código aberto com o Pepino.

https://cucumber.io/

Eu realmente não estou impressionado com a verdadeira utilidade do teste que escrevi, zombando da camada de acesso a dados e não atingindo o banco de dados. O objeto retornado não atingiu o banco de dados e não foi preenchido com dados. Era um objeto inteiramente vazio que eu tinha que zombar de uma maneira não natural. Eu apenas acho que é uma perda de tempo.

De acordo com o Stack Overflow, a zombaria é usada quando objetos reais são impraticáveis ​​para serem incorporados no teste de unidade.

https://stackoverflow.com/questions/2665812/what-is-mocking

"A zombaria é usada principalmente no teste de unidade. Um objeto em teste pode ter dependências de outros objetos (complexos). Para isolar o comportamento do objeto que você deseja testar, substitua os outros objetos por zombarias que simulam o comportamento dos objetos reais. Isso é útil se os objetos reais não forem práticos para incorporar no teste de unidade ".

Meu argumento é que, se eu estiver codificando algo de ponta a ponta (UI da web para camada comercial, camada de acesso a dados e banco de dados, ida e volta), antes de fazer o check-in como desenvolvedor, testarei esse fluxo de ida e volta. Se eu cortar a interface do usuário, depurar e testar esse fluxo a partir de um teste, testarei tudo que estiver fora da interface e retornarei exatamente o que a interface do usuário espera. Tudo o que me resta é enviar à interface do usuário o que ele deseja.

Eu tenho um teste mais completo que faz parte do meu fluxo de trabalho de desenvolvimento natural. Para mim, esse deve ser o teste de maior prioridade que cobre o teste das especificações reais do usuário, de ponta a ponta, o máximo possível. Se eu nunca criar outros testes mais detalhados, pelo menos eu tenho esse teste mais completo que prova que minha funcionalidade desejada funciona.

Um co-fundador do Stack Exchange não está convencido dos benefícios de ter 100% de cobertura de teste de unidade. Eu também não sou. Eu faria um "teste de integração" mais completo que atinge o banco de dados, mantendo vários zombarias de banco de dados a qualquer dia.

https://www.joelonsoftware.com/2009/01/31/from-podcast-38/

user3198764
fonte
é tão óbvio que você não entende a diferença entre os testes de unidade e de integração #
30517
Eu acho que depende do projeto. Em projetos menores, com menos recursos, em que um desenvolvedor é o principal responsável pelos testes e regressões por falta de testadores e por manter a documentação sincronizada com o código, se vou gastar algum tempo escrevendo testes, serão aqueles que me dá o maior retorno pelo meu dinheiro. Eu quero matar o maior número de pássaros com uma pedra possível. Se a maioria das minhas lógicas e erros vem de procedimentos armazenados no banco de dados que estão gerando relatórios ou do JavaScript front-end, ter uma cobertura total de testes de unidade na camada intermediária não ajuda muito.
user3198764
-1

Dependências externas devem ser zombadas porque você não pode controlá-las (elas podem passar durante a fase de teste de integração, mas falham na produção). As unidades podem falhar, as conexões com o banco de dados podem falhar por várias razões, pode haver problemas de rede, etc. Fazer testes de integração não oferece confiança extra, pois são todos os problemas que podem ocorrer no tempo de execução.

Com testes de unidade verdadeiros, você está testando dentro dos limites da sandbox e deve ficar claro. Se um desenvolvedor escreveu uma consulta SQL que falhou no QA / PROD, isso significa que eles nem a testaram uma vez antes desse período.

vidalsasoon
fonte
+1 para "você não pode controlá-los (eles podem passar durante a fase de teste de integração, mas falham na produção)" .
Tulains Córdova
Você pode controlá-los em grau satisfatório.
el.pescado
Entendi seu ponto de vista, mas acho que isso costumava ser mais verdadeiro do que é hoje? Com a automação e as ferramentas (como o Docker), você pode replicar e repetir a instalação de todas as suas dependências binárias / do servidor com precisão e confiabilidade para suítes de teste de integração. Obviamente, sim, o hardware físico (e serviços de terceiros etc.) pode falhar.
mindplay.dk
5
Eu absolutamente não concordo. Você deve escrever testes de integração (adicionais) porque as dependências extenais podem falhar. Dependências externas podem ter suas próprias peculiaridades, das quais você provavelmente sentirá falta quando zombar de tudo.
Paul Kertscher
1
O @PaulK ainda está pensando em qual resposta marcar como aceito, mas estou me inclinando para a mesma conclusão.
mindplay.dk