Игнорировать виртуальные свойства
У нас есть проект 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
это не подходящее место для этого. Любые другие идеи?
Ответы
Ответ 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
- это необходимо сделать вручную, если необходимо