Shim DbContext ctor для модульного тестирования усилий

Я хотел бы перехватить var context = new MyDbContext() вместо этого вернуть другой вызов конструктора.

Отличительной особенностью EFfort является то, что он позволяет вам создать простую базу данных в памяти для модульного тестирования.

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

Но тогда вам придется ввести это context в ваш репозиторий.

public FooRepository(MyDbContext context) { _context = context; }

Можно ли просто перехватить var context = new MyDbContext(), так что он возвращает testContext?

using (var context = new MyDbContext()) {
    // this way, my code isn't polluted with a ctor just for testing
}

2 ответа

Решение

(редактировать: я только что понял, что это на самом деле не возвращает другой вызов ctor. работает над этим.)

Догадаться. Достаточно просто, если вы знаете, как это сделать:

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

            // Act


            // Assert

        }

И, как обычно, EFfort требует этот конструктор в классе DbContext:

public class SomeDbContext
{
    public SomeDbContext() : base("name=Prod")
    {
    }

    // EFfort unit testing ctor
    public SomeDbContext(DbConnection connection) : base(connection, contextOwnsConnection: true) {
        Database.SetInitializer<SolrDbContext>(null);
    }
}

Но это означает, что репо, к счастью, не знает о специальном переходном соединении:

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
        }
    }
}

У вас есть два возможных варианта. Использование фабрик или Aspect-ориентированное программирование (например, PostSharp)

ссылка на эту статью: http://www.progware.org/Blog/post/Interception-and-Interceptors-in-C-(Aspect-oriented-programming).aspx

Использование PostSharp (AOP)

PostSharp - отличный инструмент, который может обеспечить максимально чистый перехват (то есть никаких изменений в ваших классах и генерации объектов вообще, даже если вы не используете фабрики для создания объектов и / или интерфейсов), но это не бесплатная библиотека. Вместо того, чтобы создавать прокси во время выполнения, он внедряет код во время компиляции и, следовательно, изменяет исходную программу, добавляя перехват методов.
.....
Крутая вещь в этом заключается в том, что вы ничего не меняете в своем коде, поэтому ваш объект все еще может быть сгенерирован с использованием нового ключевого слова.

Использование DI и Factory-pattern

Лично я предпочитаю подход фабричного образца, но вам кажется, что вам нужно вводить какие-либо зависимости в ваши классы.

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(); 
    }
}
Другие вопросы по тегам