4

在最近关于存根的问题中,许多答案建议使用 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 的构造函数添加了一个新的失败路径(分配可能会失败)。

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

4

6 回答 6

3

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

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

于 2008-09-18T21:44:19.417 回答
2

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

于 2008-09-18T21:27:15.933 回答
1

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

坏坏。

于 2008-09-18T21:34:16.023 回答
1

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

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

if (globals.isTest)
于 2008-09-18T21:36:26.330 回答
1

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

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

于 2008-09-19T14:48:57.387 回答
0

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

于 2008-09-18T21:36:12.290 回答