1

我有一个与 MSpec 一起使用的基类,它提供了围绕 AutoMock 的便捷方法:

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 无法解析,并且无法从此 LifetimeScope 创建嵌套生命周期,因为它已被释放。

我猜这与 MSpec 运行测试的方式(通过反射)有关,并且有一段时间没有主动引用 AutoMock 使用的底层生命周期范围内的任何对象,这会导致生命周期范围得到处置。这里发生了什么,我有什么简单的方法可以防止它发生吗?

4

1 回答 1

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>在错误的时间被调用并导致您痛苦的问题。

于 2015-07-21T21:51:17.630 回答