2010-08-18 2 views
2

Я пытаюсь использовать AutoMoqCustomization с AutoFixture для создания контроллера ASP.NET MVC2 в модульном тесте через Fixture. CreateAnonymous. Я пробовал в xUnit в TestDriven.NET, графическом интерфейсе xUnit и в MSTest, и все имеют одинаковый результат: массивный сбой процесса, выполняющего тест. В Windows 7 x64, если это имеет значение.Метод Fixture.CreateAnonymous убивает процесс тестового запуска с ошибкой (AutoFixture) при использовании AutoMoq для создания контроллера

Чтобы воспроизвести, просто создать новый проект ASP.NET MVC2, добавьте ссылки на AutoFixture, AutoMoq и Moq (3.1, согласно источнику AutoMoq) и попробовать (REPRO VS2010 MVC2 ссылку проекта ниже) ниже:

[TestMethod] 
public void Index() 
{ 
var fixture = new Fixture().Customize(new AutoMoqCustomization()); 
    // here's where the error in the test host occurs: 
HomeController controller = fixture.CreateAnonymous<HomeController>(); 
} 

В MSTest ошибка читает:

среда обнаружена фатальная ошибка. Адрес ошибки был равен 0x6465f370, в потоке 0x2684. Код ошибки: 0xc0000005. Эта ошибка может быть ошибкой в ​​CLR или в небезопасных или не поддающихся проверке частях кода пользователя. Общие источники этой ошибки включают ошибки маршалинга пользователя для COM-interop или PInvoke, которые могут повредить стек.

AfWithMvc repro project (from SkyDrive)

ответ

3

Предложенное решение

Для начала возможного решения, это должно остановить сбоями:

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.

Благодарим за сообщение об этом.

+0

Спасибо, это отличное объяснение и исправление. Для чего это стоит, я согласен с вашей идеей о том, что IntPtr следует охранять, но не нужно добавлять специальную поддержку делегатов - кажется ненужным. – ZeroBugBounce

+0

Хорошо, я играл с fixture.Inject > (..), а между этим и источником MVC2 выяснилось, что структура MVC требует, чтобы null был возвращен в какой-то момент от этого Func в качестве терминатора/сигнала. Это может быть возврат null от начала или возврата n строк, а затем null. – ZeroBugBounce

 Смежные вопросы

  • Нет связанных вопросов^_^