En supposant une interface IReader, une implémentation de l'interface IReader ReaderImplementation et une classe ReaderConsumer qui consomme et traite les données du lecteur.
public interface IReader
{
object Read()
}
la mise en oeuvre
public class ReaderImplementation
{
...
public object Read()
{
...
}
}
Consommateur:
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
}
}
Pour tester ReaderConsumer et le traitement, j'utilise une maquette d'IReader. ReaderConsumer devient donc:
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
}
}
}
Dans cette solution, le mocking introduit une phrase if pour le code de production car seul le constructeur mocking fournit des instances de l'interface.
Lors de l'écriture, je me rends compte que le bloc try-finally est quelque peu indépendant car il est là pour gérer l'utilisateur qui change l'emplacement pendant l'exécution de l'application.
Dans l'ensemble, il sent mal, comment pourrait-il être mieux géré?
mocking
code-smell
kristian mo
la source
la source
ReaderConsumer
indépendantReaderImplementation
?Réponses:
Au lieu d'initialiser le lecteur à partir de votre méthode, déplacez cette ligne
Dans le constructeur sans paramètre par défaut.
Il n'y a pas de "constructeur factice", si votre classe a une dépendance dont elle a besoin pour fonctionner, alors le constructeur devrait soit lui fournir cette chose, soit la créer.
la source
Vous n'avez besoin que d'un seul constructeur:
dans votre code de production:
dans votre test:
la source
Examiner l'injection de dépendance et l'inversion du contrôle
Ewan et RubberDuck ont tous deux d'excellentes réponses. Mais je voulais mentionner un autre domaine à examiner, à savoir l'injection de dépendance (DI) et l'inversion de contrôle (IoC). Ces deux approches déplacent le problème que vous rencontrez dans un framework / bibliothèque afin que vous n'ayez pas à vous en soucier.
Votre exemple est simple et est rapidement supprimé, mais, inévitablement, vous allez vous en inspirer et vous vous retrouverez avec des tonnes de constructeurs ou des routines d'initialisation qui ressemblent à:
var foo = new Foo (new Bar (new Baz (), new Quz ()), new Foo2 ());
Avec DI / IoC, vous utilisez une bibliothèque qui vous permet d'énoncer les règles pour faire correspondre les interfaces aux implémentations, puis vous dites simplement "Donnez-moi un Foo" et cela fonctionne comment câbler le tout.
Il y a beaucoup de conteneurs IoC très sympathiques (comme on les appelle), et je vais recommander un à regarder, mais, veuillez explorer, car il y a beaucoup de bons choix.
Un simple pour commencer est:
http://www.ninject.org/
Voici une liste à explorer:
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
la source