Estou trabalhando para tornar minhas aulas testáveis por unidade, usando injeção de dependência. Mas algumas dessas classes têm muitos clientes e não estou pronto para refatorar todas elas para começar a passar nas dependências ainda. Então, eu estou tentando fazer isso gradualmente; mantendo as dependências padrão por enquanto, mas permitindo que elas sejam substituídas para teste.
Uma abordagem que estou discutindo é apenas mover todas as "novas" chamadas para seus próprios métodos, por exemplo:
public MyObject createMyObject(args) {
return new MyObject(args);
}
Em meus testes de unidade, posso apenas subclassificar essa classe e substituir as funções de criação, para que eles criem objetos falsos.
Será esta uma boa abordagem? Existem desvantagens?
Em geral, é bom ter dependências codificadas, desde que você possa substituí-las para teste? Eu sei que a abordagem preferida é explicitamente exigi-los no construtor e gostaria de chegar lá eventualmente. Mas eu estou querendo saber se este é um bom primeiro passo.
Uma desvantagem que me ocorreu: se você tem subclasses reais que precisa testar, não poderá reutilizar a subclasse de teste que escreveu para a classe pai. Você precisará criar uma subclasse de teste para cada subclasse real e ela deverá substituir as mesmas funções de criação.
Respostas:
Essa é uma boa abordagem para você começar. Observe que o mais importante é cobrir seu código existente com testes de unidade; Depois de fazer os testes, você pode refatorar mais livremente para melhorar ainda mais seu design.
Portanto, o ponto inicial não é tornar o design elegante e brilhante - apenas para tornar a unidade de código testável com as mudanças menos arriscadas . Sem testes de unidade, você deve ser extremamente conservador e cauteloso para evitar a quebra de seu código. Essas alterações iniciais podem até fazer o código parecer mais desajeitado ou feio em alguns casos - mas, se permitirem que você escreva os primeiros testes de unidade, poderá refatorar para o design ideal que você tem em mente.
O trabalho fundamental para ler sobre esse assunto é Trabalhar efetivamente com o código legado . Ele descreve o truque que você mostra acima e muitos, muitos mais, usando vários idiomas.
fonte
O pessoal da Guice recomenda usar
para todas as propriedades, em vez de apenas adicionar @Inject à sua definição. Isso permitirá que você os trate como beans normais, que podem ser
new
testados (e configurados manualmente) e @Inject na produção.fonte
Quando me deparo com esse tipo de problema, identificarei cada dependência da minha classe a ser testada e criarei um construtor protegido que permitirá que eu as passe. É efetivamente o mesmo que criar um setter para cada um, mas prefiro declarar dependências em meus construtores para que eu não esqueça de instancia-las no futuro.
Portanto, minha nova classe de unidade testável terá 2 construtores:
fonte
Você pode considerar o idioma "getter cria" até poder usar a dependência injetada.
Por exemplo,
Isso permitirá refatorar internamente para que você possa referenciar seu myObject através do getter. Você nunca precisa ligar
new
. No futuro, quando todos os clientes estiverem configurados para permitir a injeção de dependência, basta remover o código de criação em um único local - o getter. O setter permitirá que você injete objetos simulados, conforme necessário.O código acima é apenas um exemplo e expõe diretamente o estado interno. Você deve considerar cuidadosamente se essa abordagem é apropriada para sua base de código.
Também recomendo que você leia " Trabalhando efetivamente com o código herdado ", que contém várias dicas úteis para obter sucesso em uma grande refatoração.
fonte