Para o projeto em que minha equipe e eu estamos trabalhando, geralmente descobrimos que precisamos de grandes partes do código do andaime. Criar objetos de domínio com valores corretos, configurar simulações para repositórios, lidar com o cache, ... são coisas que ocorrem geralmente durante os testes. Muitas vezes, trabalhamos com os mesmos objetos básicos que são centrais para o nosso domínio (pessoa, ...), portanto muitos testes criam instâncias desses objetos para outros objetos trabalharem. Como temos muitas soluções diferentes usando o domínio base, esse tipo de código geralmente se espalha por essas soluções.
Eu estive pensando em criar classes comuns que fazem muito desse andaime. Isso nos permitiria solicitar uma pessoa totalmente instanciada com tudo configurado (acesso via repositório, armazenamento em cache ...). Isso remove o código duplicado de nossos testes de unidade individuais, mas também significa que há uma grande quantidade de código que provavelmente faz 'muito' por teste (pois configuraria um objeto completo e não apenas as partes necessárias).
Alguém já fez isso? Existem insights, comentários, pensamentos ... você pode oferecer que possa validar ou invalidar essa abordagem?
fonte
Respostas:
Eu uso o padrão do construtor para criar objetos de domínio para testes, conforme detalhado no livro " Growing Object-Oriented Software ". Os construtores têm métodos estáticos que geram valores padrão para objetos comuns com métodos para substituir os valores padrão.
Você pode combiná-los para gerar objetos mais complexos.
Também usamos a herança de classe de caso de teste com zombarias comumente usadas para tipos específicos de testes de unidade - por exemplo, os testes do controlador mvc frequentemente exigem os mesmos zombarias / stubs para objetos de solicitação e resposta.
fonte
A configuração de todos os testes pode ser uma boa ideia, principalmente se você fizer uma implantação. Em vez de usar zombarias, criamos, implantamos e preenchemos um banco de dados de teste e, em seguida, apontamos o teste para a instância. Não exatamente da maneira que você deve fazer de acordo com o manual, mas funciona, ainda mais para nós, porque usamos o nosso código de implantação para fazê-lo.
fonte
Bedwyr Humphreys está falando sobre uma solução Builder que eu usei algumas vezes, e realmente funciona bem. Quase nenhuma duplicação de código e construção de objetos de domínio de uma maneira limpa e agradável.
Eu não sou tão fã de geração de código (andaimes, codesmith, lblgen, ..). Isso ajuda você a escrever códigos duplicados muito mais rapidamente, não sendo realmente de manutenção. Se uma estrutura estiver fazendo com que você escreva muitos códigos duplicados (de teste), talvez seja necessário encontrar uma maneira de afastar a base de código da estrutura.
Se você continuar escrevendo o código de acesso ao repositório, poderá resolvê-lo com um repositório básico genérico e ter uma classe de teste básica genérica da qual seus testes de unidade herdam.
Para evitar duplicação de código, o AOP também pode ajudar em coisas como log, cache, ...
fonte
Você pode reconsiderar o design do código que está testando. Talvez ele precise de algumas instâncias do padrão de design do Facade? Seu código de teste poderia usar as Fachadas e seria mais simples.
fonte
Eu posso me relacionar com essa pergunta. Na minha equipe, tentamos fazer o TDD antes e era a mesma história, muitos testes exigiam muitos métodos de andaimes / utilitários que simplesmente não tínhamos. Por causa das pressões do tempo e poucas outras decisões não tão corretas, acabamos com testes de unidade muito longos e reinventamos as coisas. Ao longo de um lançamento, esses testes de unidade tornaram-se tão complicados e difíceis de manter, que tivemos que descartá-los.
Atualmente, estou trabalhando com alguns outros desenvolvedores na reintrodução do TDD de volta à equipe, mas, em vez de simplesmente dizer às pessoas, fazer testes, queremos fazê-lo com cuidado dessa vez e as pessoas têm as habilidades e as ferramentas certas. Ausência do código de suporte comum é uma coisa que identificamos onde precisamos melhorar, para que, quando outros começarem a escrever testes, todo o código que eles escreverem seja pequeno e direto ao ponto.
Ainda não tenho tanta experiência nesta área quanto gostaria, mas poucas coisas que sugiro com base no trabalho que fizemos até agora e em alguns trabalhos de casa que fiz:
fonte
"Qualquer problema na ciência da computação pode ser resolvido com uma camada adicional de indireção. Mas isso geralmente cria outro problema". - David Wheeler
(aviso: faço parte da equipe da JDT, por isso tenho um conhecimento mais aprofundado do problema apresentado aqui)
O problema essencial aqui é que os próprios objetos na estrutura esperam uma conexão com o banco de dados, pois é vagamente baseado na estrutura CSLA de Rockford Lhotka. Isso torna quase impossível zombar deles (já que você precisaria alterar a estrutura para suportar isso) e também viola o princípio da caixa preta que um teste de unidade deve ter.
Sua solução proposta, embora não seja uma má idéia, exigirá não apenas muito trabalho para chegar a uma solução estável, mas também adicionará outra camada de classes que precisam ser mantidas e estendidas, adicionando ainda mais complexidade a uma solução já existente. situação complexa.
Embora eu concorde que você deve sempre procurar a melhor solução, em uma situação do mundo real como essa, ser prático também tem seus valores.
E praticidade sugere a seguinte opção:
Use um banco de dados.
Sim, eu sei que tecnicamente falando não é mais um teste de unidade "real", mas estritamente falando no momento em que você ultrapassa um limite de classe em seu teste, também não é mais um teste de unidade real. O que precisamos nos perguntar aqui é: queremos testes de unidade 'puros' que exijam grande quantidade de andaimes e códigos de cola, ou queremos código testável ?
Você também pode usar o fato de que a estrutura usada encapsula todo o acesso ao banco de dados e executar seus testes em um banco de dados de sandbox limpo. Se você executar cada teste em sua própria transação e reverter no final de cada conjunto "lógico" de testes, não deverá ter problemas de interdependência ou ordem de teste.
Não tente extrair um banco de dados de um banco de dados.
fonte
Eu alertaria por ter muito código que faz muita 'magia negra' sem que os desenvolvedores saibam exatamente o que está sendo configurado. Além disso, com o tempo, você se tornará muito dependente desse código / dados. É por isso que não sou fã de basear seus testes em bancos de dados de teste. Acredito que os bancos de dados de teste são para teste como usuário, não para testes automatizados.
Dito isto, seu problema é real. Eu faria alguns métodos comuns para configurar os dados necessários regularmente. Idealmente, tente parametrizar os métodos, porque determinados testes precisam de dados diferentes.
Mas eu evitaria criar grandes gráficos de objetos. É melhor executar testes com o mínimo de dados que eles precisam. Se houver muitos outros dados, você poderá influenciar inesperadamente os resultados do teste (pior cenário).
Eu gosto de manter meus testes o mais "possível". É uma questão subjetiva, no entanto. Mas eu usaria métodos comuns com parâmetros para que você possa configurar seus dados de teste em apenas algumas linhas de código.
fonte
Todas as possibilidades resumidas nas respostas:
Use o padrão Builder (Bedwyr Humphreys, DXM e Pascal Mestdach)
Vantagens:
Desvantagens:
Use um banco de dados de teste (Tony Hopkinson e Sam)
Vantagens:
Desvantagens:
Criar objetos de domínio por teste (Peter)
Vantagens:
Desvantagens:
Usar Fachadas para objetos de domínio (Raedwald)
Vantagens:
Desvantagens:
fonte