Предложенное решение
Для начала возможного решения, это должно остановить сбоями:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
// This should fix the problem for all Controllers
fixture.Customize<ViewDataDictionary>(c =>
c.Without(x => x.ModelMetadata));
HomeController controller = fixture.CreateAnonymous<HomeController>();
Объяснение
А теперь для объяснения:
Эта ошибка теста вызвана AutoFixture в AutoProperties художественных пытается присвоить значение HomeController.ViewData.ModelMetaData
. Класс ModelMetaData имеет этот конструктор:
public ModelMetadata(
ModelMetadataProvider provider,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
виновник здесь является параметром modelAccessor
. Для того, чтобы заполнить эту собственность AutoFixture (а бездумно) отражает над типом и находит этот единственный конструктор:
public Func(object @object, IntPtr method)
Копаем дальше, первый IntPtr конструктор AutoFixture может удовлетворить это один:
public unsafe IntPtr(int value)
По умолчанию, Int32 instances are created by a deterministic rising sequence, поэтому value
в этом случае, вероятно, будет 1 или 2 или аналогичное маленькое целое число. Другими словами, теперь у нас есть очень недействительный небезопасный указатель на наших руках, и это приводит к сбою процесса.
Теперь, при нормальных обстоятельствах мы должны быть в состоянии исправить это путем регистрации Func<object>
с Крепеж и все должно быть денди:
fixture.Register<Func<object>>(() =>() => new object());
Однако, я попытался это с Repro и хотя этот процесс уже не сбой аналогичным образом, проверка выполняется очень долго и, наконец, сбой OutOfMemoryException.
Я не знаю, что делает ASP.NET MVC с Func<object>
, но, по-видимому, он использует его довольно тяжелый.
Вопрос остается, является ли это ошибкой в AutoFixture?
Я считаю, что это не так. Хотя он определенно не идеален, AutoFixture не обрабатывает Funcs или Actions иначе, чем другие типы, поэтому мы видим это поведение.
Это конкретное поведение могло быть решено путем добавления конкретной поддержки для Func<TResult>
, но оставаться последовательным он также должен иметь поддержку Func<T, TResult>
, Func<T1, T2, TResult>
и т.д. AFAIR в .NET 4 есть намного этих типов делегатов (также Action и т. д.), так что это означает добавление поддержки для целого множества типов.
Но как насчет всех других типов, которые принимают IntPtr в их конструкторе? AutoFixture, возможно, не знает о них всех, так что это не похоже на жизнеспособное направление.
Однако, что это может есть guard that prevents it from attempting to create IntPtr instances in the first place. Скорее всего, это будет добавлено до 2.0 RTW.
Благодарим за сообщение об этом.
Спасибо, это отличное объяснение и исправление. Для чего это стоит, я согласен с вашей идеей о том, что IntPtr следует охранять, но не нужно добавлять специальную поддержку делегатов - кажется ненужным. – ZeroBugBounce
Хорошо, я играл с fixture.Inject> (..), а между этим и источником MVC2 выяснилось, что структура MVC требует, чтобы null был возвращен в какой-то момент от этого Func