我在业务逻辑内部遇到了NSubstitute的使用(在测试分类之外):
var extension = Substitute.For<IExtension>();
当您需要模拟某些类(接口)时,我习惯于在测试类中利用NSubstitute。但是在测试类之外使用NSubstitute使我感到困惑。这是正确的地方吗?使用像依赖注入容器这样的NSubstitute是正确的,它可以创建接口/类的实例吗?
我担心的是NSubstitute设计用于测试。测试内部的性能不是很重要,这就是为什么它可能很慢的原因。而且,它依赖于反射,因此不可能很快。但是,NSubstitute的性能不好吗?
还有其他原因,为什么不应该在测试之外使用NSubstitute或其他模拟库?
答案 0 :(得分:3)
不,在生产代码中使用模拟库通常不是一个好习惯。 (我将在这里大量使用“一般”,因为我认为关于“良好实践”的任何问题都需要一定程度的概括。人们可能会提出反对这种概括的案例,但我认为这些案例将是少数。)
即使不考虑性能,模拟库也会为接口/类创建测试实现。测试实现通常支持一些功能,例如记录调用并存入特定调用以返回特定结果。通常,当我们具有用于生产代码的接口或类时,它是为了达到某些特定目的,而不是记录调用和存根返回值的一般目的。
虽然可以使用NSubstitute为接口提供特定的实现,并且可以对执行生产代码逻辑的每个调用进行存根,但为什么不创建具有所需实现的类呢?
这通常具有以下优点:
特别是对于NSubstitute来说,有一些重要的原因导致您永远不要在生产代码中使用它。因为该库是为测试代码设计的,所以它使用了一些生产代码不可接受的方法:
sub.MyCall()
返回一个int
。像sub.MyCall().Returns(42)
这样的调用进行存根意味着我们正在调用int.Returns(42)
,这现在将以某种方式影响正在被调用的int
之外的调用的返回值。这与C#/ VB通常的工作方式完全不同。总结:您的编程语言提供了为实现逻辑接口而设计和优化的结构。您的模拟库提供了为更有限的任务而设计和优化的构造,这些任务提供了逻辑接口的测试实现,以便与测试代码结合使用,而与其依赖关系无关。除非您出于铁定的理由而进行编程,就像用纸而不是铲子挖一个洞一样,我建议您将每种工具用于预期的用途。 :)