Ich habe eine Methode in meiner Datenzugriffsschicht, die Mapping durchführt. Die Methode akzeptiert einen DataReader und ordnet die Daten den richtigen Domänenobjekteigenschaften zu. Gibt es eine gute Möglichkeit, irgendwie mock der DataReader, so dass ich Unit-Tests auf die Mapping-Methoden durchführen können, ohne gegen eine physische Datenbank zu schlagen?
Antworten
Zu viele Anzeigen?Zum Glück für Sie, DataReader
implementiert die IDataReader
Schnittstelle.
Anstatt sich auf eine DataReader
in Ihrem Code, verwenden Sie IDataReader
. In Ihren Tests können Sie dann Ihre eigene Implementierung ersetzen, die Dummy-Daten zurückgibt, oder Sie verwenden ein Mocking-Framework wie Rhino.Mocks oder ähnliches, um die Stubs zu erstellen und Rückgabewerte zuzuweisen.
Je nachdem, wie Sie die DataReader
in Ihrem Code zu finden, müssen Sie möglicherweise eine kleine Umstrukturierung vornehmen. Was Sie wollen, ist, dass externe Abhängigkeiten wie diese in den Konstruktor (bevorzugt) oder durch eine Eigenschaft "injiziert" werden, so dass die Benutzer der Klasse jede Implementierung von IDataReader
. (Diese Substitution ist auch der Grund, warum Sie Ihre Parameter/Eigenschaften als Abstraktionen und nicht als konkrete Typen deklarieren). Dies ist bekannt als Injektion von Abhängigkeiten , eine Form der Umkehrung der Kontrolle .
Wenn Sie den IDataReader nachahmen wollen, um eine Liste von Datensätzen zurückzugeben, können Sie eine Klasse erstellen, die IDataReader implementiert und einige ihrer Methoden (wie Read() und Indexer) außer Kraft setzen. Außerdem benötigen Sie eine Variable, die die aktuelle Zeile aufzeichnet, und eine Variable, die die Listenwerte enthält. Nachfolgend finden Sie den Beispielcode für diese Vorgehensweise:
public class MockDataReader : IDataReader
{
private int _rowCounter = 0;
private List<Dictionary<string,object>> _records = new List<Dictionary<string,object>>();
public MockDataReader(List<Dictionary<string,object>> records)
{
_records = records;
}
public bool Read()
{
_rowCounter++;
if (_rowCounter < _records.Count) return true;
return false;
}
public object this[string name]
{
get { return _records[_rowCounter][name]; }
}
}
Um diese Klasse zu nutzen, können Sie den folgenden Code verwenden:
var itemsList = new List<Dictionary<string, object>>();
for (int i = 0; i < 5; i++)
{
var num = i + 1;
var items = new Dictionary<string, object>();
items.Add("Id", num);
items.Add("FirstName", "MyFirstName" + num);
items.Add("LastName", "MyLastName" + num);
itemsList.Add(items);
}
var result = new MockDataReader(itemsList);
Das ist nicht ganz sicher, aber es funktioniert. Ich hoffe, es hilft :)
Ja, verwenden Sie nicht DataReader
pero IDataReader o IDataRecord dann spottet, was ihr wollt.