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

时间:2015-06-25 14:45:18

标签: c# unit-testing nsubstitute automocking

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

Test Under Class 实例是使用AutoSubstitute构建的,以便自动阻止所有需要的依赖项。

AutoSubstitute autoSubstitute = new AutoSubstitute();

MainPanelViewModel viewModel = autoSubstitute.Resolve<MainPanelViewModel>();

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

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

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

viewModel.Received().ActivateItem(Arg.Any<SomeSpecificScreenType>());

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

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

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

  

NSRestitute扩展方法,如.Received()只能在使用Substitute.For()和相关方法创建的对象上调用。

2 个答案:

答案 0 :(得分:1)

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

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

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

HTH

答案 1 :(得分:1)

为了完整起见,我做了一些NSubstitute用ForPartsOf部分替换的实验。

ForPartsOf的工作方式主要是定义一个新类,该类继承自您用作模板的类。这限制了模拟框架可以截取到定义为abstractvirtual的方法的内容。如果您要使用自己的类继承它,则与修改类的行为有同样的限制。

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

base.ActivateItem(nextScreen);

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

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

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

ActivateItem(nextScreen)

你根本无法拦截这个:

base.ActivateItem(nextScreen);

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

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