在最近关于存根的问题中,许多答案建议使用 C# 接口或委托来实现存根,但是 一个答案 建议使用条件编译,在生产代码中保留静态绑定。这个答案在阅读时被修改为-2,所以至少有 2 人真的认为这是一个 错误的 回答。也许滥用 DEBUG 是原因,或者可能使用固定值而不是更广泛的验证。但我不禁想知道:

使用条件编译是否是实现单元测试存根的不适当技术?有时?总是?

谢谢。

编辑-添加: 我想添加一个示例作为实验:

class Foo {
    public Foo() { .. }
    private DateTime Now { 
      get {
#if UNITTEST_Foo
        return Stub_DateTime.Now;
#else
        return DateTime.Now;
#endif
      }
    }
    // .. rest of Foo members
}

相比于

interface IDateTimeStrategy { 
    DateTime Now { get; }
}
class ProductionDateTimeStrategy : IDateTimeStrategy {
  public DateTime Now { get { return DateTime.Now; } }
}
class Foo {
    public Foo() : Foo(new ProductionDateTimeStrategy()) {}
    public Foo(IDateTimeStrategy s) { datetimeStrategy = s; .. }
    private IDateTime_Strategy datetimeStrategy;
    private DateTime Now { get { return datetimeStrategy.Now; } }
}

这允许通过 C# 接口对“DateTime.Now”的传出依赖进行存根。然而,我们现在添加了一个动态调度调用,其中静态就足够了,即使在生产版本中对象也更大,并且我们为 Foo 的构造函数添加了一个新的失败路径(分配可能会失败)。

我在这里什么都不用担心吗?感谢迄今为止的反馈!

有帮助吗?

解决方案

尝试将生产代码与测试代码分开。维护不同的文件夹层次结构..不同的解决方案/项目。

除非..您正处于遗留 C++ 代码的世界中。这里什么都可以..if 条件块可以帮助您获得一些可测试的代码,并且您会看到好处..无论如何都要这样做。但尽量不要让它变得比初始状态更混乱。清晰地注释和划分条件块。谨慎行事。这是一种在测试工具下获取遗留代码的有效技术。

其他提示

我认为这降低了人们审查代码的清晰度。您不必记住特定代码周围有一个条件标记来理解上下文。

不,这太可怕了。它将测试泄漏到您的生产代码中(即使其条件关闭)

糟糕糟糕。

测试代码应该是显而易见的,并且不要与测试代码混合在同一块中。

这与你不应该写的原因几乎相同

if (globals.isTest)

我想到了另一个可怕的原因:

很多时候,您模拟/存根某些东西,您希望它的方法根据您正在测试的内容返回不同的结果。这要么排除了这一点,要么让它变得非常尴尬。

当您在大型代码库中重构可测试性时,它可能会作为一种有用的工具来依靠。我可以看到您如何使用此类技术来实现较小的更改并避免“大爆炸”重构。然而,我会担心过于依赖这种技术,并会尽力确保此类技巧不会在代码库中存在太久,否则您可能会面临使应用程序代码变得非常复杂且难以遵循的风险。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top