如何使用 AutofacContrib.NSubstitute 监视正在测试的 class
How to spy the class under test with AutofacContrib.NSubstitute
我正在运行 class 库项目中使用 NSpec 框架进行单元测试,AutofacContrib.NSubstitute v3.3.2.0,NSubstitute v1.7.0.0(最新版本现在是 1.8.2).
Class Under Test 实例是用 AutoSubstitute
构建的,以便自动模拟其所有需要的依赖项。
AutoSubstitute autoSubstitute = new AutoSubstitute();
MainPanelViewModel viewModel = autoSubstitute.Resolve<MainPanelViewModel>();
如果工作正常,我的 Class Under Test 在某些时候会调用其中一个带有特定输入参数的基本 class 方法(基本 class 不在我的控制范围内):
// ...
base.ActivateItem(nextScreen);
// ...
因此,为了测试预期,我需要检查(侦测)该实例是否调用了基本方法:
viewModel.Received().ActivateItem(Arg.Any<SomeSpecificScreenType>());
问题是:当我尝试这样做时,在运行时 NSubstitute 抱怨说我只能 运行 Received()
反对使用 Substitute.For<>()
创建的对象。我也快速检查了 AutofacContrib.NSubstitute 源代码,但我找不到一种方法来获取带有自动模拟的实例,同时 wrap 它以某种方式在间谍对象或类似的东西中那。
我也认为 Substitute.ForPartsOf<>()
可能会有帮助,但 NSubstitute v1.7.0 中似乎没有找到该方法。
为了完整起见,这里是 NSubstitute 的完整错误:
NSubstitute extension methods like .Received() can only be called on objects created using Substitute.For() and related methods.
所以,实际问题并没有真正解决:只是问题本身消失了。
为了检查正确的行为,我记得我还可以求助于基数 class 的 ActiveItem
public 属性,所以我停止了使用 Receive()
并返回到简单的值比较。
不过,为了将来参考,我没有找到一种方法来监视 Class Under Test 与这些库。我知道应该避免监视正在测试的 class,但与许多事情一样,有时您需要这样做。
HTH
为了完整起见,我用 ForPartsOf
对 NSubstitute 的部分替换做了一些实验。
ForPartsOf
的工作方式本质上是定义一个新的 class,它继承自您用作模板的 class。这将模拟框架可以拦截的内容限制为定义为 abstract
或 virtual
的方法。如果您要用自己的 class.
从它继承,这与修改 class 的行为所具有的限制相同。
根据这些信息,让我们看看您的问题。你想拦截这个电话:
base.ActivateItem(nextScreen);
因此,由于上述限制,为了能够拦截对 ActivateItem
的调用,该方法必须在基础 class 中标记为 virtual
。如果不是,那么在不更改应用程序结构的情况下,什么都做不了。
如果该方法被标记为virtual
,那么您可以使用NSubstitute 拦截它但是您只能在调用NSubstituted 实现时执行此操作。这是通过正常的方法分派来工作的,因为当你调用它时,虚方法的最高层实现被调用(由 NSubstitute 提供)。但是,当您通过 base
引用调用方法时它不起作用。
所以,虽然你可以拦截这个:
ActivateItem(nextScreen)
你根本无法拦截这个:
base.ActivateItem(nextScreen);
您在代码中使用 base.ActivateItem
的事实表明您的 class 被测有其自己不想调用的方法的实现,因此您当前的您无法实现您想要做的事情的工具。这就是为什么您找到 .
是一件好事
您与大多数其他模拟框架(包括 Moq. The exception is TypeMock)处于相同的情况,它使用完全不同的方式来拦截方法调用,这意味着它可以做其他框架根本做不到的事情。
我正在运行 class 库项目中使用 NSpec 框架进行单元测试,AutofacContrib.NSubstitute v3.3.2.0,NSubstitute v1.7.0.0(最新版本现在是 1.8.2).
Class Under Test 实例是用 AutoSubstitute
构建的,以便自动模拟其所有需要的依赖项。
AutoSubstitute autoSubstitute = new AutoSubstitute();
MainPanelViewModel viewModel = autoSubstitute.Resolve<MainPanelViewModel>();
如果工作正常,我的 Class Under Test 在某些时候会调用其中一个带有特定输入参数的基本 class 方法(基本 class 不在我的控制范围内):
// ...
base.ActivateItem(nextScreen);
// ...
因此,为了测试预期,我需要检查(侦测)该实例是否调用了基本方法:
viewModel.Received().ActivateItem(Arg.Any<SomeSpecificScreenType>());
问题是:当我尝试这样做时,在运行时 NSubstitute 抱怨说我只能 运行 Received()
反对使用 Substitute.For<>()
创建的对象。我也快速检查了 AutofacContrib.NSubstitute 源代码,但我找不到一种方法来获取带有自动模拟的实例,同时 wrap 它以某种方式在间谍对象或类似的东西中那。
我也认为 Substitute.ForPartsOf<>()
可能会有帮助,但 NSubstitute v1.7.0 中似乎没有找到该方法。
为了完整起见,这里是 NSubstitute 的完整错误:
NSubstitute extension methods like .Received() can only be called on objects created using Substitute.For() and related methods.
所以,实际问题并没有真正解决:只是问题本身消失了。
为了检查正确的行为,我记得我还可以求助于基数 class 的 ActiveItem
public 属性,所以我停止了使用 Receive()
并返回到简单的值比较。
不过,为了将来参考,我没有找到一种方法来监视 Class Under Test 与这些库。我知道应该避免监视正在测试的 class,但与许多事情一样,有时您需要这样做。
HTH
为了完整起见,我用 ForPartsOf
对 NSubstitute 的部分替换做了一些实验。
ForPartsOf
的工作方式本质上是定义一个新的 class,它继承自您用作模板的 class。这将模拟框架可以拦截的内容限制为定义为 abstract
或 virtual
的方法。如果您要用自己的 class.
根据这些信息,让我们看看您的问题。你想拦截这个电话:
base.ActivateItem(nextScreen);
因此,由于上述限制,为了能够拦截对 ActivateItem
的调用,该方法必须在基础 class 中标记为 virtual
。如果不是,那么在不更改应用程序结构的情况下,什么都做不了。
如果该方法被标记为virtual
,那么您可以使用NSubstitute 拦截它但是您只能在调用NSubstituted 实现时执行此操作。这是通过正常的方法分派来工作的,因为当你调用它时,虚方法的最高层实现被调用(由 NSubstitute 提供)。但是,当您通过 base
引用调用方法时它不起作用。
所以,虽然你可以拦截这个:
ActivateItem(nextScreen)
你根本无法拦截这个:
base.ActivateItem(nextScreen);
您在代码中使用 base.ActivateItem
的事实表明您的 class 被测有其自己不想调用的方法的实现,因此您当前的您无法实现您想要做的事情的工具。这就是为什么您找到
您与大多数其他模拟框架(包括 Moq. The exception is TypeMock)处于相同的情况,它使用完全不同的方式来拦截方法调用,这意味着它可以做其他框架根本做不到的事情。