Подтвердить что ты не робот

Игнорировать виртуальные свойства

У нас есть проект MVC4 с Entity Framework для хранения. Для наших тестов мы недавно начали использовать Autofixture, и это действительно потрясающе.

Наш график моделей очень глубок и обычно создает один объект AutoFixture, который создает весь график: Person → Team → Departments → Company → Contracts → .... и т.д.

Проблема с этим - время. Создание объекта занимает до одной секунды. И это приводит к медленным испытаниям.

То, что я нахожу, что я много делаю, это такие вещи:

        var contract = fixture.Build<PersonContract>()
            .Without(c => c.Person)
            .Without(c => c.PersonContractTemplate)
            .Without(c => c.Occupation)
            .Without(c => c.EmploymentCompany)
            .Create<PersonContract>();

И это работает, и это быстро. Но эта сверх-спецификация делает тесты трудными для чтения, и иногда я теряю важные детали, такие как .With(c => c.PersonId, 42), в списке несущественных .Without().

Все эти игнорируемые объекты являются навигационными свойствами для Entity Framework, и все они являются виртуальными.

Есть ли глобальный способ сказать AutoFixture игнорировать виртуальные члены?

Я попытался создать ISpecimentBuilder, но не повезло:

public class IgnoreVirtualMembers : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {

        if (request.GetType().IsVirtual // ?? this does not exist )
        {
             return null;
        }
    }
}

Я не могу найти способ в ISpecimenBuilder, чтобы обнаружить, что объект, который мы создаем, является виртуальным членом в другом классе. Вероятно, ISpecimenBuilder это не подходящее место для этого. Любые другие идеи?

4b9b3361

Ответ 1

Читайте немного больше о блоге Mark (это особенно) Я нашел способ сделать то, что хочу:

/// <summary>
/// Customisation to ignore the virtual members in the class - helps ignoring the navigational 
/// properties and makes it quicker to generate objects when you don't care about these
/// </summary>
public class IgnoreVirtualMembers : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var pi = request as PropertyInfo;
        if (pi == null)
        {
            return new NoSpecimen(request);
        }

        if (pi.GetGetMethod().IsVirtual)
        {
            return null;
        }
        return new NoSpecimen(request);
    }
}

И вы можете обернуть их в настройку:

public class IgnoreVirtualMembersCustomisation : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(new IgnoreVirtualMembers());
    }
}

Итак, в вашем тесте вы просто выполните:

var fixture = new Fixture().Customize(new IgnoreVirtualMembersCustomisation());

и создайте свои сложные модели.

Наслаждайтесь!

Ответ 2

У меня была такая же проблема, и я решил сделать еще один шаг и создать настройку для ленивых навигационных свойств. Проект находится на Github и NuGet.

Рассмотрим простой граф объектов, который имеет круговую зависимость:

class Foo
{
    public int Id { get; set; }
    public int BarId { get; set; }
    public virtual Bar Bar { get; set; }
}

class Bar
{
    public int Id { get; set; }
    public int FooId { get; set; }
    public virtual Foo Foo { get; set; }
}

При этой настройке вызов var foo = fixture.Create<Foo>() создаст объект типа Foo. Вызов геттера foo.Bar будет использовать DynamicProxy и AutoFixture для создания экземпляра Bar на лету и назначения его этому свойству. Последующие вызовы foo.Bar возвращают один и тот же объект.

N.B. настройка не достаточно умна, чтобы установить foo.Bar.Foo = foo - это необходимо сделать вручную, если необходимо