条件编译是单元测试的有效模拟/存根策略吗?

Aar*_*ron 5 unit-testing stub conditional-compilation

在最近关于存根的问题中,许多答案建议使用 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
}
Run Code Online (Sandbox Code Playgroud)

相比于

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; } }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Gis*_*shu 3

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

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