Можно ли заморозить макет функции?

Я хочу проверить, что мой тип Func действительно выполняется. Для этого я создал Mock, но столкнулся с Exception из Autofixture. Я пробовал Freeze только Func (без Mock), и это работает. Может кто-нибудь объяснить, что происходит, или направить меня на правильный способ сделать это?

Сообщение об исключении:

Исключение типа «Ploeh.AutoFixture.Kernel.IllegalRequestException» возникло в Ploeh.AutoFixture.dll, но не было обработано в пользовательском коде. Дополнительная информация: Обнаружен запрос IntPtr. Это небезопасный ресурс, использование которого приведет к сбою процесса, поэтому запрос будет отклонен. Распространенным источником запросов IntPtr являются запросы делегатов, таких как Func или Action. В этом случае ожидаемый обходной путь — настроить (зарегистрировать или внедрить) проблемный тип, указав правильную стратегию создания.

Код:

public class DomainClassDummy
{
    public int Id { get; set; }
}

var frozenFunc = F.Freeze<Func<int, DomainClassDummy>>(); //works
var frozenMockOfFunc = F.Freeze<Mock<Func<int,DomainClassDummy>>>(); //fails 

person Flodpanter    schedule 29.07.2015    source источник
comment
Какие версии Moq и AutoFixture вы используете? Вы настраиваете Fixture или используете его как есть?   -  person Marcio Rinaldi    schedule 29.07.2015
comment
Я использую Autofixture 3.30.8 и настраиваю его: F = new Fixture().Customize(new AutoConfiguredMoqCustomization());   -  person Flodpanter    schedule 30.07.2015


Ответы (2)


Такое поведение связано с AutoConfiguredMoqCustomization.

Когда AutoFixture настраивается с помощью AutoConfiguredMoqCustomization, он передает создание экземпляров Mock специальному компоновщику. Однако этот конструктор получает внутренний тип Func<int,DomainClassDummy> и создает из него мокап, передавая два аргумента своего конструктора: object и IntPtr, и вот в чем проблема.

Построитель по умолчанию для делегатов создает свои экземпляры из лямбда-выражения Linq.

Чтобы заставить его работать, вам нужно будет создать макет самостоятельно и внедрить его в AutoFixture. Его внедрение аналогично замораживанию, за исключением того, что вы сами указываете экземпляр, а не указываете AutoFixture создать его для вас.

Вот что вы должны сделать:

var mockOfFunc = new Mock<Func<int, DomainClassDummy>>();
F.Inject(mockOfFunc);
person Marcio Rinaldi    schedule 30.07.2015

Объяснение, данное Марсио Ринальди, технически верно, но я нашел решение неудовлетворительным, поэтому я добавил эту возможность в AutoFixture.AutoMoq 3.31.1.

Теперь этот тест проходит:

[Fact]
public void FixtureCanFreezeUsableMockOfFunc()
{
    // Fixture setup
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var expected = fixture.Create<Uri>();
    var mockOfFunc = fixture.Freeze<Mock<Func<Guid, decimal, Uri>>>();
    mockOfFunc
        .Setup(f => f(It.IsAny<Guid>(), 1337m))
        .Returns(expected);

    // Exercise system
    var actual = mockOfFunc.Object(Guid.NewGuid(), 1337m);

    // Verify outcome
    Assert.Equal(expected, actual);
    // Teardown
}
person Mark Seemann    schedule 02.08.2015
comment
Ух ты. Это именно то, что я ищу. Я попробую это. Спасибо. - person Flodpanter; 07.08.2015