Aufwand - FirstOrDefault gibt null zurück, wenn Datenbank falsch gemacht wird

c# effort entity-framework mocking unit-testing

Frage

Ich versuche, ein paar Komponententests für mein Projekt zu erstellen, nachdem ich viel geforscht habe, habe ich Mühe gefunden, die Idee ist großartig, sie verspottet die Datenbank, anstatt sich mit dem DBContext zu täuschen, was übrigens sehr schwierig ist, es richtig zu machen Verwenden eines komplexen Schemas.

Ich versuche jedoch, die E-Mail von einem Benutzer zu erhalten, nachdem ich es speziell zur In-Memory-Datenbank von Effort hinzugefügt habe, hier ist der Code

MyContext contextx = new MyContext(Effort.DbConnectionFactory.CreateTransient());

var client = new Client
{
    ClientId = 2,
    PersonId = 3,
    Person = new Person
    {
        PersonId = 3,
        EMail = "xxxxx@gmail.com"
    }
};
contextx.Client.Add(client); //<-- client got added, I checked it and is there

var email = contextx.Client.Select(c => c.Person.EMail).FirstOrDefault(); 

In der letzten Zeile oben kann ich es nicht schaffen, die Email xxxx@gmail.com zurück zu geben, stattdessen gibt es immer null zurück.

Irgendwelche Ideen?

Akzeptierte Antwort

Beantworten Sie Ihre direkte Frage

Für die spezifische Frage, die Sie gestellt haben, würde ich zwei Dinge vorschlagen:

  1. contextx.Client.ToArray() Sie sich contextx.Client.ToArray() und sehen Sie, wie viele Mitglieder Sie wirklich in dieser Sammlung haben. Es kann sein, dass die Client Sammlung tatsächlich leer ist. In diesem Fall erhalten Sie tatsächlich null. Oder es könnte sein, dass das erste Element in der Client-Sammlung einen Nullwert für EMail .

  2. Wie ändert sich das Verhalten, wenn Sie contextx.SaveChanges() vor dem Abfragen der Client Auflistung auf dem DbContext aufrufen? Ich bin gespannt, ob der Aufruf von SaveChanges führt, dass der neu eingefügte Wert in der Sammlung vorhanden ist. Dies sollte eigentlich nicht erforderlich sein, aber es könnte eine seltsame Interaktion zwischen Effort und dem DbContext .

EDIT: SaveChanges() erweist sich als die Antwort.

Allgemeine Testvorschläge

Da Sie diese Frage mit dem Tag "unit-testing" tabbediert haben, biete ich einige allgemeine Testempfehlungen an, die auf meinen zehn Jahren als Unit Testing Practitioner und Coach basieren. Beim Komponententest werden verschiedene kleine Teile Ihrer Anwendung isoliert getestet. In der Regel bedeutet dies, dass Komponententests nur mit wenigen Klassen gleichzeitig interagieren. Dies bedeutet auch, dass Komponententests nicht von externen Bibliotheken oder Abhängigkeiten (wie der Datenbank) abhängig sein sollten. Umgekehrt übt ein Integrationstest mehr Teile des Systems auf einmal aus und kann externe Abhängigkeiten von Dingen wie Datenbanken haben.

Dies mag zwar wie ein Wortspiel über die Terminologie erscheinen, aber die Begriffe sind wichtig, um die tatsächliche Absicht Ihrer Tests anderen Mitgliedern Ihres Teams zu vermitteln.

In diesem Fall möchten Sie entweder einen Teil der Funktionalität testen, der / das von DbContext abhängig ist, oder Sie versuchen, Ihre Datenzugriffsebene zu testen. Wenn Sie versuchen, einen isolierten Komponententest für etwas zu schreiben, das direkt vom DbContext abhängt, müssen Sie die Abhängigkeit vom DbContext aufheben. Ich werde das unten in Breaking the Dependency auf DbContext unten erklären. Andernfalls versuchen Sie wirklich, den DbContext-Integrationstest zu testen, einschließlich der Zuordnung Ihrer Entitäten. In diesem Fall habe ich es immer am besten gefunden, diese Tests zu isolieren und eine echte (lokale) Datenbank zu verwenden. Wahrscheinlich möchten Sie eine lokal installierte Datenbank derselben Sorte verwenden, die Sie in der Produktion verwenden. Oft funktioniert SqlExpress gut. Richten Sie Ihre Tests auf eine Instanz der Datenbank, die die Tests vollständig auswerfen können. Lassen Sie Ihre Tests alle vorhandenen Daten entfernen, bevor Sie jeden Test ausführen. Dann können sie alle benötigten Daten einrichten, ohne dass bestehende Daten in Konflikt geraten.

Die Abhängigkeit von DbContext brechen

Also, wie schreibt man gute DbContext , wenn Ihre Geschäftslogik vom Zugriff auf DbContext abhängig ist? Du nicht.

In meinen Anwendungen, die Entity Framework für die Datenpersistenz verwenden, stelle ich sicher, dass der Zugriff auf den DbContext in einem separaten Datenzugriffsprojekt enthalten ist. Normalerweise werde ich Klassen erstellen, die das Repository-Muster implementieren, und diese Klassen können eine Abhängigkeit von DbContext . In diesem Fall würde ich ein ClientRepository erstellen, das eine IClientRepository Schnittstelle implementiert. Die Schnittstelle würde ungefähr so ​​aussehen:

public interface IClientRepository {

    Client GetClientByEMail(string email);

}

Dann können alle Klassen, die Zugriff auf die Methode benötigen, mit einem einfachen Stub / Mock / was auch immer getestet werden. Nichts muss sich darum sorgen, DbContext . Ihre Datenzugriffsebene ist enthalten und Sie können sie mit einer echten Datenbank gründlich testen. Einige Vorschläge zum Testen Ihrer Datenzugriffsebene finden Sie oben.

Als zusätzlichen Vorteil definiert die Implementierung dieser Schnittstelle, was es bedeutet, einen Client per E-Mail-Adresse an einem einzigen, einheitlichen Ort zu finden. Mit der IClientRepository Schnittstelle können Sie schnell die Frage "Wie IClientRepository wir nach Client Entitäten in unserem System?" Beantworten.

Die Abhängigkeit von DbContext ist in etwa so DbContext ein DbContext da Domänenklassen eine Abhängigkeit von der Verbindungszeichenfolge erhalten und überall ADO.Net-Code haben. Das bedeutet, dass Sie einen echten Datenspeicher (sogar mit einer falschen Datenbank) mit echten Daten erstellen müssen. Wenn Sie jedoch Ihren Zugriff auf den DbContext innerhalb einer bestimmten Datenzugriffsbaugruppe enthalten, werden Sie feststellen, dass Ihre DbContext viel einfacher zu schreiben sind.

Was die Projektorganisation betrifft, erlaube ich meinem Datenzugriffsprojekt normalerweise nur, einen Verweis auf Entity Framework zu nehmen. Ich werde ein separates Core-Projekt haben, in dem ich die Entitäten definiere. Ich werde auch die Datenzugriffsschnittstellen im Core-Projekt definieren. Dann werden die konkreten Schnittstellenimplementierungen in das Datenzugriffsprojekt eingefügt. Die meisten Projekte in Ihrer Lösung können dann einfach vom Core-Projekt abhängig sein, und nur das ausführbare Programm oder das Webprojekt der obersten Ebene muss wirklich vom Datenzugriffsprojekt abhängig sein.




Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum