In einem unserer Projekte verwenden wir Linq to Sql für die Arbeit mit Datenbanken. Es ist wirklich sehr praktisch, denn es ermöglicht Ihnen, eine Datenbank mit Linq abzufragen.
Alles ist in Ordnung, bis Sie Ihren Code einem Unit-Test unterziehen wollen... Wie spottet man DataContext? Nicht so einfach. DataContext implementiert keine Schnittstelle, Table ist versiegelt. Was ist zu tun?
Ich habe schon eine Weile nach einer Lösung gesucht, es gibt viele verschiedene Ansätze. Ich zeige Ihnen, was ich am nützlichsten fand und was recht einfach zu implementieren ist.
Die Lösung ist, wie immer, eine Abstraktion zu schaffen. Ich habe also eine Schnittstelle zur Abstraktion des DataContext erstellt und sie in einem DataContext partial implementiert. Die Schnittstelle definiert Methoden zur Abfrage der Datenbank und zum Speichern unserer Änderungen (Einfügen, Aktualisieren, Löschen). Die Klasse Table ist versiegelt, so dass ich sie nicht nachahmen kann und sie auch nicht in der Schnittstelle offenlegen kann. Für mich ist es am besten, wenn ich die Tabellen von DataContext über IQueryable offenlege, um sie abzufragen. Das erlaubt mir die Verwendung von Linq und bietet außerdem die Möglichkeit, lazy/eager loading durchzuführen. Zum Speichern von Änderungen - vier Methoden: InsertOnSubmit(), UpdateOnSubmit(), DeleteOnSubmit() und natürlich SubmitChanges(). So, das ist die Schnittstelle.
public interface IDataContext
{
public T Tabelle<T>();
public void InsertOnSubmit(T entity);
public void UpdateOnSubmit(T entity, T originalEntity);
public void DeleteOnSubmit(T entity);
public void SubmitChanges();
}
Sie können ihn fast genauso verwenden, wie Sie DataContext direkt verwenden würden.
var Kunde = Kontext.Tabelle<Kunde>() .Where(x => x.Name == "Kunde1") .Single(); customer.Name = "newCustomerName"; context.SubmitChanges();
Die Implementierung in der Teilklasse DataContext ist wie folgt.
public partial class MyDataContext : IDataContext
{
public T Tabelle<T>()
{
return GetTable<T>();
}
public void InsertOnSubmit<T>(T Entität) wobei T : Klasse
{
if (null != Entität)
this.GetTable<T>().InsertOnSubmit(entity);
}
public void UpdateOnSubmit<T>(T Entität, T originalEntität) wobei T : Klasse
{
if (null != Entität)
this.GetTable<T>().Attach(entity, originalEntity);
}
public void DeleteOnSubmit<T>(T Entität) wobei T : Klasse
{
if (null != Entität)
this.GetTable<T>().DeleteOnSubmit(entity);
}
}
Das ist doch ziemlich einfach und kurz zu implementieren, oder? Jetzt können Sie Ihre Datenbank ohne Probleme nachbilden. Beispiel mit der Moq-Bibliothek:
var customerList = new Liste<Kunde>(); //Kundenliste auffüllen var context = new Mock<IDataContext>(); Kontext .Setup(x => x.Tabelle<Kunde>()) .Returns(customerList.AsQueryable());
Wir geben mit unserem Mock eine Liste zurück, Linq to Objects erledigt den Rest. Es besteht natürlich das Risiko, dass sich der Linq-Anbieter für Linq to Sql anders verhält als der Anbieter für Linq to Objects, aber in meinen Tests funktioniert es sehr gut.
Wenn Ihr Code (den Sie testen möchten) viele Tabellen verwendet, kann die Einrichtung des Tests ziemlich lang sein (Codezeilen). In einer solchen Situation ist es besser, einen generischen Mock-Kontext zu schreiben, der wie eine In-Memory-Datenbank funktioniert. Ich habe dies auch getan und werde es in einem anderen Beitrag zeigen.
Das ist also alles. Viel Spaß!
Unsere Ideen
Weitere Blogs
Contact



