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.
public FooRepository(MyDbContext context) { _context = context; }
Ist es möglich, var context = new MyDbContext()
einfach abzufangen, so dass es den testContext
?
using (var context = new MyDbContext()) {
// this way, my code isn't polluted with a ctor just for testing
}
(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:
public class SomeDbContext
{
public SomeDbContext() : base("name=Prod")
{
}
// EFfort unit testing ctor
public SomeDbContext(DbConnection connection) : base(connection, contextOwnsConnection: true) {
Database.SetInitializer<SolrDbContext>(null);
}
}
Aber es bedeutet, dass der Repo die spezielle transiente Verbindung glücklicherweise nicht kennt:
public class SomeRepository
{
public void SomeMethodName()
{
using (var context = new SomeDbContext())
{
// self-contained in repository, no special params
// and still calls the special test constructor
}
}
}
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
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.
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();
}
}