如何使用AutofacContrib.NSubstitute监视测试中的类

我正在使用NSpec框架,AutofacContrib.NSubstitute v3.3.2.0,NSubstitute v1.7.0.0(最新版本为1.8.2)的类库项目中运行unit testing。

Class Under Test实例是使用AutoSubstitute ,以便自动锁定所有需要的依赖项。

 AutoSubstitute autoSubstitute = new AutoSubstitute(); MainPanelViewModel viewModel = autoSubstitute.Resolve(); 

如果工作正常,我的Class Under Test会在某个时候调用其中一个基类方法,并带有一些特定的输入参数(基类不在我的控制范围内):

 // ... base.ActivateItem(nextScreen); // ... 

因此,对于测试期望,我需要检查(间谍)实例调用基本方法:

 viewModel.Received().ActivateItem(Arg.Any()); 

这是问题:当我尝试这样做时,在运行时NSubstitute抱怨我只能对使用Substitute.For()创建的对象运行Received() Substitute.For() 。 我还快速检查了AutofacContrib.NSubstitute源代码,但我找不到一种方法来获取具有自动锁定的实例,同时它以某种方式包装在间谍对象或类似的东西中。

我也认为也许Substitute.ForPartsOf()可能会有所帮助,但在NSubstitute v1.7.0中似乎找不到该方法。

为了完整起见,这里的NSubstitute完全错误:

像.Received()这样的NSubstitute扩展方法只能在使用Substitute.For()和相关方法创建的对象上调用。

为了完整起见,我做了一些NSubstitute与ForPartsOf部分替换的ForPartsOf

ForPartsOf工作方式主要是定义一个新类,该类inheritance自您用作模板的类。 这限制了virtual框架可以拦截到被定义为abstractvirtual 。 如果您要使用自己的类inheritance它,则与修改类的行为相同。

获取此信息,让我们看看您的问题。 你想拦截这个电话:

 base.ActivateItem(nextScreen); 

因此,由于上述限制,为了能够拦截对ActivateItem的调用,该方法必须在基类中标记为virtual 。 如果不是,那么在不改变应用程序结构的情况下,你无能为力。

如果该方法被标记为virtual ,那么您可以使用NSubstitute拦截它, 只有在调用NSubstituted实现时才能执行此操作。 这通过常规方法分派来工作,因为在调用虚拟方法时,会调用虚拟方法的最高级别实现(NSubstitute提供的实现)。 但是,当您通过base引用调用方法时,它不起作用。

所以,虽然你可以拦截这个:

 ActivateItem(nextScreen) 

你根本无法拦截这个:

 base.ActivateItem(nextScreen); 

您在代码中使用base.ActivateItem这一事实表明您的测试类具有您自己不想调用的方法的实现,因此使用您当前的工具无法实现您的尝试做。 这就是为什么你找到一个解决方法是一件好事。

与大多数其他模拟框架(包括Moq)处于相同的情况。 exception是TypeMock ,它使用一种完全不同的方法来拦截方法调用,这意味着它可以执行其他框架根本无法做到的事情。

所以,实际问题还没有真正解决:只是问题本身就消失了。

为了检查正确的行为,我回忆起我也可以从基类求助于一个ActiveItem公共属性,所以我停止使用Receive()并返回到简单的值比较。

尽管如此,为了将来参考,我还没有找到一种方法来监视这些库中的Class Under Test。 我知道应该避免监视被测试的课程,但是就像许多事情一样,有时你需要这样做。

HTH