为什么Autofac mock的生命周期在一个简单的MSpec测试中处理?

时间:2015-07-21 20:03:13

标签: autofac mspec automocking

我有一个我正在使用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使用的基础生命周期范围内的任何对象的时间。使生命望远镜处理掉。这里发生了什么,是否有一些简单的方法可以防止它发生?

1 个答案:

答案 0 :(得分:1)

模拟本身处置时,AutoMock的{​​{1}}生命周期范围将被处理。如果你得到这个,这意味着Autofac.Extras.Moq实例已经被处置或者已经丢失范围,GC已经清理了它。

鉴于此,有一些可能性。

第一种可能性是你在异步方法调用方面遇到了一些潜在的线程挑战。看看被模拟的方法,我看到你正在验证对AutoMock方法的调用。但是,我没有在其中看到任何异步相关代码,并且我不完全确定在给定当前发布的代码的情况下运行的测试何时/如何调用它,但是如果存在异步调用导致测试的情况当SaveFileAsync失去范围或者在另一个线程上被杀死时,在一个线程上运行,我可以看到这种情况发生。

第二种可能性是上下文中的静态和实例项的混合。您将AutoMock存储为静态,但它所在的上下文类似乎是一个基类,旨在提供与实例相关的值。例如,如果两个测试并行运行,则第一个测试会将AutoMock设置为它认为需要的值,然后第二个测试将覆盖AutoMock,第一个测试将超出范围,处置范围。

第三种可能性是在一次测试中多次调用AutoMock 。对BuildSubject<T>的调用会初始化BuildSubject<T>。如果您在一次测试中多次调用,尽管更改了AutoMock类型,您每次都会踩T,并且将关联相关的生命周期范围。

第四种可能性是测试订购问题。如果您有时只看到它而不是其他时间,那么某些测试可能会无意中假设某些设置(如对AutoMock的调用)已经完成;而其他测试可能不会做出这种假设,并会自己调用BuildSubject<T>。根据测试运行的顺序,有时候你可能会很幸运而没有看到异常,但有时候你可能会遇到在错误的时间调用BuildSubject<T>而导致痛苦的问题。