Angenommen, eine IReader-Schnittstelle, eine Implementierung der IReader-Schnittstelle ReaderImplementation und eine Klasse ReaderConsumer, die Daten vom Reader verwendet und verarbeitet.
public interface IReader
{
object Read()
}
Implementierung
public class ReaderImplementation
{
...
public object Read()
{
...
}
}
Verbraucher:
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
}
}
Zum Testen von ReaderConsumer und der Verarbeitung verwende ich einen IReader-Mock. So wird ReaderConsumer:
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
}
}
}
In dieser Lösung führt Mocking einen if-Satz für den Produktionscode ein, da nur der Mocking-Konstruktor Instanzen der Schnittstelle bereitstellt.
Während des Schreibens wird mir klar, dass der try-finally-Block in keiner Beziehung steht, da er dazu dient, den Benutzer beim Ändern des Speicherorts während der Laufzeit der Anwendung zu unterstützen.
Insgesamt riecht es, wie könnte es besser gehandhabt werden?
mocking
code-smell
kristian mo
quelle
quelle
ReaderConsumer
unabhängig zu machenReaderImplementation
?Antworten:
Verschieben Sie diese Zeile, anstatt den Reader von Ihrer Methode aus zu initialisieren
In den Standardkonstruktor ohne Parameter.
Es gibt keinen "Scheinkonstruktor". Wenn Ihre Klasse über eine Abhängigkeit verfügt, die für die Arbeit erforderlich ist , sollte dem Konstruktor entweder dieses Objekt bereitgestellt oder es erstellt werden.
quelle
Sie benötigen nur den einzelnen Konstruktor:
In Ihrem Produktionscode:
in deinem test:
quelle
Untersuchen Sie Abhängigkeitsinjektion und Inversion der Steuerung
Sowohl Ewan als auch RubberDuck haben hervorragende Antworten. Aber ich wollte noch einen anderen Bereich erwähnen, in dem es um Abhängigkeitsinjektion (DI) und Inversion of Control (IoC) geht. Bei beiden Ansätzen wird das aufgetretene Problem in ein Framework / eine Bibliothek verschoben, sodass Sie sich darüber keine Gedanken machen müssen.
Ihr Beispiel ist einfach und schnell erledigt, aber Sie werden unweigerlich darauf aufbauen, und Sie werden entweder Tonnen von Konstruktoren oder Initialisierungsroutinen haben, die so aussehen:
var foo = new Foo (neuer Balken (new Baz (), new Quz ()), new Foo2 ());
Mit DI / IoC verwenden Sie eine Bibliothek, mit der Sie die Regeln für das Zuordnen von Schnittstellen zu Implementierungen formulieren können. Dann sagen Sie einfach "Give me a Foo" und es wird herausgefunden, wie alles verkabelt wird.
Es gibt viele sehr freundliche IoC-Container (wie sie genannt werden), und ich werde einen empfehlen, den man sich ansehen kann, aber bitte erkundigen Sie sich, da es sehr viele gute Möglichkeiten gibt.
Ein einfacher Einstieg ist:
http://www.ninject.org/
Hier ist eine Liste zum Erkunden:
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
quelle