2015-07-21 5 views
1

У меня есть базовый класс, я использую с MSpec который предоставляет удобные методы вокруг AutoMock:Почему это время жизни Autofac mock в простой проверке MSpec?

public abstract class SubjectBuilderContext 
{ 
    static AutoMock _container; 

    protected static ISubjectBuilderConfigurationContext<T> BuildSubject<T>() 
    { 
     _container = AutoMock.GetLoose(); 
     return new SubjectBuilderConfigurationContext<T>(_container); 
    } 

    protected static Mock<TDouble> GetMock<TDouble>() 
     where TDouble : class 
    { 
     return _container.Mock<TDouble>(); 
    } 
} 

Иногда я вижу исключение произойдет при попытке извлечь Mock, как так:

It should_store_the_receipt =() => GetMock<IFileService>().Verify(f => f.SaveFileAsync(Moq.It.IsAny<byte[]>(), Moq.It.IsAny<string>()), Times.Once()); 

Вот исключение:

System.ObjectDisposedExceptionInstances не могут быть решены, и вложенные время жизни не может быть Creat из этого LifetimeScope, поскольку он уже был удален .

Я предполагаю, что это что-то делать с тем, как MSpec проходит испытания (с помощью отражения), и что есть период времени, когда ничего активно не имеют ссылок на любой из объектов в подлежащем пожизненного объема используемого AutoMock, который заставляет lifetimecope удаляться. Что здесь происходит, и есть ли какой-то простой способ избежать этого?

+0

Звучит как e идеально подходит для [MFakes] (https://github.com/machine/Machine.Fakes) для меня. Он должен абстрагироваться от насмешливых фреймворков и их тонкостей. Есть ли причина, по которой вы не используете MFakes? –

+0

Спасибо за рекомендацию. Я могу взглянуть на MFakes более внимательно, но я хотел бы прояснить, что происходит с моим использованием AutoMocks, прежде всего, в надежде не повторить ту же ошибку в другом контексте позже. –

ответ

1

AutoMock срок службы от Autofac.Extras.Moq расположен, когда сам макет находится. Если вы получаете это, это означает, что экземпляр AutoMock был удален или иным образом потерял область действия, и GC очистил его.

Учитывая, что существует несколько возможностей.

Первая возможность заключается в том, что у вас есть потенциальные проблемы с потоками при вызове асинхронного вызова. Глядя на метод, который насмехается, я вижу, что вы проверяете вызов метода SaveFileAsync. Тем не менее, я не вижу никакого асинхронного кода там, и я не совсем уверен, когда/как запущенные тесты вызывают его, учитывая текущий опубликованный код, но если есть ситуация, когда асинхронный вызов вызывает тест, запускать на одном потоке, в то время как AutoMock теряет область действия или иным образом убивается на другом потоке, я мог видеть это.

Вторая возможность - сочетание статических и экземпляров элементов в контексте. Вы сохраняете AutoMock как статичный, но, похоже, класс контекста, в котором он находится, является базовым классом, который предназначен для предоставления значений, связанных с экземпляром. Если два теста выполняются параллельно, например, первый тест установит AutoMock на то, что он считает нужным, тогда второй тест перезапишет AutoMock, и первый из них выйдет из сферы действия, удалив область действия.

Третья возможность - Несколько звонков на номер BuildSubject<T> в одном тесте. Призыв к BuildSubject<T> инициализирует AutoMock. Если вы назовете это несколько раз за один тест, несмотря на изменение типа T, вы будете топать AutoMock каждый раз, и связанная с ним продолжительность жизни будет удалена.

Четвертая возможность - Задача проверки порядка. Если вы видите это иногда, но не в другое время, может быть, что некоторые тесты непреднамеренно предполагают, что некоторые настройки, такие как вызов BuildSubject<T>, уже выполнены; в то время как другие тесты не могут сделать это предположение и сами вызовут BuildSubject<T>.В зависимости от порядка выполнения тестов вам иногда может повезти и не видеть исключения, но в других случаях вы можете столкнуться с проблемой, когда BuildSubject<T> вызывается в самое неподходящее время и вызывает у вас боль.

+0

Спасибо за ответ, Трэвис. Я считаю, что теперь я могу исключить первую теорию относительно сценария, имеющую какое-либо отношение к async (по крайней мере, как единственную причину), так как теперь я вижу это с неасинхронными методами. Я также думаю, что могу устранить вторую теорию, основанную на этом ответе от Alexander Groß, которая показывает, что тесты MSpec запускаются серийно: http://stackoverflow.com/questions/14865859/how-is-static-object-state-shared-set- между-mspec контекстов. Я могу подтвердить, что в третьей и четвертой теориях не так (множественные или отсутствующие вызовы BuildSubject). –

+0

Ну, где-то вдоль линии, AutoMock становится доступным. Без ваших фактических тестов и повторного воспроизведения все, что я могу сделать, это догадываться о том, как это сделать. –

+0

Я обновлю, чтобы предоставить всю необходимую информацию. –

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