Shim DbContext ctor für das Testen von Testeinheiten


Frage

Ich möchte var context = new MyDbContext() abfangen, um stattdessen einen anderen Konstruktoraufruf zurückzugeben.

Das Schöne an EFfort ist, dass Sie eine einfache In-Memory-Datenbank für Komponententests einrichten können.

var connection = Effort.DbConnectionFactory.CreateTransient();
var testContext = new MyDbContext(connection);

Aber dann müssten Sie diesen context in Ihr Repository einfügen.

var connection = Effort.DbConnectionFactory.CreateTransient();
var testContext = new MyDbContext(connection);

Ist es möglich, var context = new MyDbContext() einfach abzufangen, so dass es den testContext ?

var connection = Effort.DbConnectionFactory.CreateTransient();
var testContext = new MyDbContext(connection);

Akzeptierte Antwort

(Bearbeiten: Ich habe gerade gemerkt, dass dies nicht wirklich den anderen ctor-Aufruf zurückgibt. Arbeiten daran.)

Herausgefunden. Einfach genug, wenn Sie wissen, wie es geht:

        [TestMethod]
        public void Should_have_a_name_like_this()
        {
            // Arrange
            var connection = Effort.DbConnectionFactory.CreateTransient();
            ShimSolrDbContext.Constructor = context => new SolrDbContext(connection);

            // Act


            // Assert

        }

Und wie üblich benötigt EFfort diesen Konstruktor in der DbContext-Klasse:

        [TestMethod]
        public void Should_have_a_name_like_this()
        {
            // Arrange
            var connection = Effort.DbConnectionFactory.CreateTransient();
            ShimSolrDbContext.Constructor = context => new SolrDbContext(connection);

            // Act


            // Assert

        }

Aber es bedeutet, dass der Repo die spezielle transiente Verbindung glücklicherweise nicht kennt:

        [TestMethod]
        public void Should_have_a_name_like_this()
        {
            // Arrange
            var connection = Effort.DbConnectionFactory.CreateTransient();
            ShimSolrDbContext.Constructor = context => new SolrDbContext(connection);

            // Act


            // Assert

        }

Beliebte Antwort

Sie haben zwei mögliche Optionen. Verwendung von Fabriken oder über aspektorientierte Programmierung (wie PostSharp)

Diesen Artikel referenzierend: http://www.progware.org/Blog/post/Interception-and-Interceptors-in-C-(Aspect-oriented-programming).aspx

Verwenden von PostSharp (AOP)

PostSharp ist ein großartiges Werkzeug und kann das sauberste Abfangen erreichen, das möglich ist (das bedeutet keine Änderungen in Ihren Klassen und der Objekterzeugung, auch wenn Sie nicht Ihre Fabriken für Objekterstellung und / oder Schnittstellen haben), aber es ist keine freie Bibliothek. Anstatt Proxies zur Laufzeit zu erstellen, injiziert es Code zur Kompilierungszeit und ändert daher Ihr initiales Programm auf nahtlose Weise, um Methodenabfangen hinzuzufügen.
.....
Das coole daran ist, dass Sie nichts anderes in Ihrem Code ändern, sodass Ihr Objekt immer noch mit dem neuen Schlüsselwort generiert werden kann.

DI und Factory-Muster verwenden

Ich persönlich bevorzuge den Factory-Pattern-Ansatz, aber Sie scheinen alle Abhängigkeiten in Ihre Klassen einfügen zu müssen.

public interface IDbContextFactory<T> where T : DbContext {
    T Create();
}

public class TestDbContextFactory : IDbContextFactory<MyDbContext> {
    public MyDbContext Create() {
        var connection = Effort.DbConnectionFactory.CreateTransient();
        var testContext = new MyDbContext(connection);
        return testContext;
    }
}

public class FooRepository {
    MyDbContext _context;
    public FooRepository(IDbContextFactory<MyDbContext> factory) { 
        _context = factory.Create(); 
    }
}




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