Как указать класс для использования при имитации свойства?

Я обнаружил, что часто подделываю IDbSet из Entity Framework. У меня обычно есть такой интерфейс:

public interface IContext : IDisposable
{
    IDbSet<Cat> Cats { get; set; }
    IDbSet<Dogs> Dogs { get; set; }
}

Который я подделываю так:

IContext context = A.Fake<IContext>();
context.Cats = new FakeDbSet<Cat>();
context.Dogs = new FakeDbSet<Dogs>();

Эти последние две строки кода становятся болью.
FakeDbSet - это пользовательский класс, который мы всегда хотим использовать вместо фейка FakeItEasy.

Есть ли какой-то способ, которым я могу просто сказать FakeItEasy, что везде, где он видит IDbSet, использовать FakeDbSet?

1 ответ

Решение

Есть ли какой-то способ, которым я могу просто сказать FakeItEasy, что везде, где он видит IDbSet, использовать FakeDbSet?

Не таким образом, нет. Существуют пользовательские Dummies, возможности которых значительно улучшатся в следующем выпуске 2.0, но в настоящее время свойства не возвращают Dummies, когда они могут возвращать поддельный тип (см. Проблему 156 для получения слишком большой информации об этом). В противном случае у вас все будет готово.

В противном случае лучший вариант на самом деле - использовать отражение, чтобы посмотреть типы возвращаемых свойств и соответственно установить значение.

Вы могли бы использовать недавно расширенные возможности IFakeConfigurator в бета-версиях 2.0 в качестве хука, чтобы включить это поведение, чтобы у каждого созданного подделки были свои свойства изучены и желаемый FakeDbSet добавлено.

Что-то вроде этого:

public class PropertiesUseFakeDbSetFakeConfigurator : FakeConfigurator<IContext>
{
    protected override void ConfigureFake(IContext fakeObject)
    {
        var fakeObjectType = fakeObject.GetType();
        var properties = fakeObjectType.GetProperties(
            BindingFlags.Public |
            BindingFlags.Instance |
            BindingFlags.GetProperty |
            BindingFlags.SetProperty);

        foreach (var propertyInfo in properties)
        {
            var propertyType = propertyInfo.PropertyType;
            if (propertyType.IsGenericType &&
                propertyType.GetGenericTypeDefinition() == typeof (IDbSet<>))
            {
                var typeInTheSet = propertyType.GetGenericArguments()[0];
                var fakeDbSetType = typeof (FakeDbSet<>).MakeGenericType(typeInTheSet);
                var fakePropertyValue = Activator.CreateInstance(fakeDbSetType);

                propertyInfo.SetValue(fakeObject, fakePropertyValue, null);
            }
        }
    }
}

сделал бы этот проход:

[Test]
public void Properties_should_be_FakeDbSets()
{
    IContext context = A.Fake<IContext>();

    Assert.That(context.Cats, Is.InstanceOf<FakeDbSet<Cat>>());
    Assert.That(context.Dogs, Is.InstanceOf<FakeDbSet<Dog>>());
}

Если у вас есть несколько классов, таких как IContext в вашем решении, вы можете реализовать IFakeConfigurator напрямую, а не используя FakeConfigurator<T>, Это требует немного больше работы, но предоставляет более сложный способ определить, какие подделки настроены. FakeConfigurator<IContext> буду настраивать только подделку IContexts.

Другие вопросы по тегам