Приспособление.CreateAnonymous метод завершает выполнение теста с ошибкой (автофиксация) при использовании AutoMoq для создания контроллера

StackOverflow https://stackoverflow.com/questions/3514102

Вопрос

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

Чтобы воспроизвести, просто создайте новый 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 (от SkyDrive)

Это было полезно?

Решение

Предлагаемое решение

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

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>();

Объяснение

А теперь перейдем к объяснению:

Эта тестовая ошибка вызвана автоматической установкой Автоматические свойства функция, пытающаяся присвоить значение HomeController.ViewData.ModelMetaData.Класс ModelMetadata имеет этот конструктор:

public ModelMetadata(
    ModelMetadataProvider provider,
    Type containerType,
    Func<object> modelAccessor,
    Type modelType,
    string propertyName)

Виновником здесь является modelAccessor параметр.Чтобы заполнить это свойство, автофиксация (довольно бездумно) отражает тип и находит этот единственный конструктор:

public Func(object @object, IntPtr method)

Копая дальше, можно сказать, что первая автофиксация конструктора IntPtr, которую может удовлетворить автофиксация, - это:

public unsafe IntPtr(int value)

По умолчанию, Экземпляры Int32 создаются с помощью детерминированной возрастающей последовательности, так что value в этом случае, вероятно, будет 1 или 2 или аналогичное маленькое целое число.Другими словами, теперь у нас есть очень недействительный небезопасный указатель у нас на руках, и это приводит к сбою процесса.

Теперь, при нормальных обстоятельствах мы могли бы исправить это, зарегистрировав Func<object> с Креплением и так все должно быть шикарно:

fixture.Register<Func<object>>(() => () => new object());

Однако я попробовал это с вашим воспроизведением, и хотя процесс больше не завершается таким же образом, тест выполняется очень долго и, наконец, завершается сбоем с OutOfMemoryException.

Я не знаю, что ASP.NET MVC делает с Func<object>, но, по-видимому, он использует его довольно интенсивно.

Остается вопрос, является ли это ошибкой в автофиксации?

Я верю, что это не так.Хотя это определенно не идеально, AutoFixture не обрабатывает функции или действия иначе, чем другие типы, вот почему мы видим такое поведение.

Это конкретное поведение, возможно, можно было бы устранить, добавив специальную поддержку для Func<TResult>, но чтобы оставаться последовательным , он также должен иметь поддержку для Func<T, TResult>, Func<T1, T2, TResult>, и т.д.AFAIR в .NET 4 есть очень много из этих типов делегирования (также Action и т.д.), Так что это означало бы добавление поддержки для целого ряда типов.

Но тогда как насчет всех других типов, которые принимают IntPtr в своем конструкторе?Автофиксация не может знать о них всех, так что это не похоже на жизнеспособное направление.

Однако, что это мог бы иметь - это защита, которая в первую очередь предотвращает попытку создания экземпляров IntPtr.Скорее всего, это будет добавлено до версии 2.0 RTW.

Спасибо вам за то, что сообщили об этом.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top