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

时间:2008-09-18 21:21:56

标签: unit-testing stub conditional-compilation

在最近一个关于存根的问题中,许多答案建议使用C#接口或委托来实现存根,但是one answer建议使用条件编译,在生产代码中保留静态绑定。这个答案在阅读时被修改为-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的构造函数添加了一个新的失败路径(分配可能失败)。

我在这里什么都不担心?感谢您的反馈!

6 个答案:

答案 0 :(得分:3)

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

除非 ..您处于遗留C ++代码的世界。这里有什么事情..如果条件块帮助你获得一些可测试的代码,你会看到一个好处..一定要做到这一点。但是尽量不要让它变得比初始状态更混乱。清楚地评论和划分条件块。谨慎行事。这是将遗留代码置于测试工具下的有效技术。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

不,这太可怕了。它会将测试泄漏到您的生产代码中(即使它已经过调整)

糟糕。

答案 3 :(得分:1)

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

这与你不应该写

的原因相同
if (globals.isTest)

答案 4 :(得分:1)

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

很多时候你会模拟/存根,你希望它的方法根据你测试的内容返回不同的结果。这要么排除了这一点,要么让它变得尴尬。

答案 5 :(得分:0)

在大型代码库中重构可测试性时,它可能是一种有用的工具。我可以看到你如何使用这些技术来实现较小的更改并避免“大爆炸”重构。但是我会担心过于依赖这种技术并试图确保这些技巧在代码库中不会存在太长时间,否则你可能会使应用程序代码变得非常复杂且难以遵循。