Supondo uma interface IReader, uma implementação da interface IReader ReaderImplementation e uma classe ReaderConsumer que consome e processa dados do leitor.
public interface IReader
{
object Read()
}
Implementação
public class ReaderImplementation
{
...
public object Read()
{
...
}
}
Consumidor:
public class ReaderConsumer()
{
public string location
// constructor
public ReaderConsumer()
{
...
}
// read some data
public object ReadData()
{
IReader reader = new ReaderImplementation(this.location)
data = reader.Read()
...
return processedData
}
}
Para testar o ReaderConsumer e o processamento, uso uma simulação do IReader. Então o ReaderConsumer se torna:
public class ReaderConsumer()
{
private IReader reader = null
public string location
// constructor
public ReaderConsumer()
{
...
}
// mock constructor
public ReaderConsumer(IReader reader)
{
this.reader = reader
}
// read some data
public object ReadData()
{
try
{
if(this.reader == null)
{
this.reader = new ReaderImplementation(this.location)
}
data = reader.Read()
...
return processedData
}
finally
{
this.reader = null
}
}
}
Nesta solução, a simulação introduz uma sentença if para o código de produção, pois apenas o construtor da simulação fornece instâncias da interface.
Ao escrever isso, percebo que o bloco try-finally não está relacionado, pois existe para lidar com o usuário alterar o local durante o tempo de execução do aplicativo.
No geral, parece mal cheiroso, como pode ser tratado melhor?
mocking
code-smell
kristian mo
fonte
fonte
ReaderConsumer
independenteReaderImplementation
?Respostas:
Em vez de inicializar o leitor a partir do seu método, mova esta linha
No construtor sem parâmetros padrão.
Não existe um "construtor simulado", se sua classe tem uma dependência necessária para funcionar, então o construtor deve fornecer essa coisa ou criá-la.
fonte
Você só precisa do construtor único:
no seu código de produção:
no seu teste:
fonte
Examinar injeção de dependência e inversão de controle
Ewan e RubberDuck têm excelentes respostas. Mas eu queria mencionar outra área para examinar qual é Injeção de Dependência (DI) e Inversão de Controle (IoC). Ambas as abordagens movem o problema que você está enfrentando para uma estrutura / biblioteca, para que você não precise se preocupar com isso.
Seu exemplo é simples e rapidamente é dispensado, mas, inevitavelmente, você vai desenvolver isso e acabar com toneladas de construtores ou rotinas de inicialização que se parecem com:
var foo = novo Foo (novo Bar (novo Baz (), novo Quz ()), novo Foo2 ());
Com o DI / IoC, você usa uma biblioteca que permite especificar as regras para combinar interfaces com implementações e então você diz "Give me a Foo" e descobre como conectar tudo isso.
Existem muitos recipientes de IoC muito amigáveis (como são chamados) por aí, e eu vou recomendar um para olhar, mas, por favor, explore, pois existem muitas opções excelentes.
Um simples para começar é:
http://www.ninject.org/
Aqui está uma lista para explorar:
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
fonte