【问题标题】:Couple of questions about unit-testing关于单元测试的几个问题
【发布时间】:2010-08-30 19:03:42
【问题描述】:

假设我们正在设计一个 Stack 类 test-first (TDD):

public class Stack<T> {
    private T[] elements = new T[16];
    private int size = 0;
    ...
}

此堆栈使用大小为 16 的内部数组来存储其元素。在您需要添加第 17 个元素之前,它会正常工作。因为我可能需要第 17 个元素,所以我决定将这个功能添加到我的堆栈中,所以我开始考虑我可以为必须添加该功能的测试起什么名字。这将是我第一个问题的主题。

我首先选择了以下形式的东西:

Should_Be_Able_To_Correctly_Increase_Its_Inner_Array_Size()

然后

Should_Handle_More_Items_Than_The_Default_Internal_Array_Size()

但经过一番思考后,我得出的结论是,也许像下面这样更合适:

Should_Double_Its_Size_Every_Time_Its_Full()

我的推理在第一种情况下必须这样做,我只说它做什么,而不是什么时候。 其次,我是在说何时添加更多项目,但我也在说明我是如何考虑实现它的(内部),这可能不正确。在我看来(我不确定我是否正确),我的测试应该是我的 SUT 与外部的可能交互,而不是它是如何在内部实现的。我说的对吗?

在我看来,第 3 个选项是最好的,因为它清楚地说明了它的作用(变大——实际上,它的大小翻了一番),什么时候做(当它满了)并且不束缚我到任何特定的实现(我可能稍后想将其更改为内部 ArrayList!)。

这让我想到了我的第二个问题:假设我为我的 Stack 类执行了所有单元测试,该类在内部使用了一个数组,并且它工作正常并且如预期的那样,如果我的测试保持不变,如果我以后想要重构并将 Array 更改为 ArrayList 或任何其他类型的数据结构?或者测试是否应该以任何方式反映这一点?我猜没有,但我不确定。

【问题讨论】:

  • 在我看来,您的测试不应该对内部工作做出假设。如果稍后您选择更改一些内部实现细节,您就不必重写所有测试。

标签: unit-testing testing tdd test-first


【解决方案1】:

在我看来(我不确定我是 正确),我的测试应该是可能的 我的 SUT 与 外观,而不是它的样子 内部实施。我说的对吗?

你是对的。如果您更改类的内部实现,则单元测试应该保持不变。如果您在外部公开任何新内容,您应该创建新的单元测试来解决这些更改。

请记住,当您设计您的课程时,您不想公开任何表明它是如何实现的。类的公共成员指示如何与之交互,现在它是如何在幕后工作的。

【讨论】:

    【解决方案2】:

    我不确定如何通过单元测试来测试内部列表或数组大小。您无法通过 Stack 接口访问它。单元测试用于测试外部合约。如果您想测试实现细节,请尝试其他方法。

    第二个问题的答案是肯定的,如果是单元测试,测试应该仍然通过。

    【讨论】:

    • 在做这种类TDD风格的时候,我会做什么样的测试呢?
    • 测试外部接口并确保它按预期工作。
    【解决方案3】:

    问问自己,你愿意为这门课付出什么。

    你或班级的消费者真的关心容量是翻倍、增加一还是增加一千?如果是这样,您应该修改接口,以便他们可以指定用于增加容量的策略:

    public Stack<T>(CapacityGrowthStyle capacityGrowthStyle) { ... }
    

    如果没有,只需编写测试来记录容量并将其保留(下面的X 是您的基础数据结构的限制):

    [Test]
    public void Can_Handle_X_Items() { ... }
    
    [Test]
    [ExpectedException(typeof(InvalidOperationException))]
    public void Cannot_Handle_More_Than_X_Items() { ... }
    

    我会类似地回答你的第二个问题:如果你的类的用户会关心它,你的测试应该只反映底层数据结构。

    【讨论】:

    • 我明白了。现在,如果我遵循 TDD 指南,我应该怎么做才能添加这个“功能”?现在我看到了,这是我的主要问题!
    • @devoured - 这是一个有趣(也很困难)的问题。如果容量增长算法对我的用户真的很重要(可能是出于性能原因),我会很想添加一个Capacity 属性以方便测试,即使用户通常自己可能不需要该属性。但我会为 API 混乱而感到遗憾。 :(
    • 但是假设我的用户不想知道它。使用测试优先的方法,如果我首先进行了测试来测试它,我应该只添加一些特定的功能。但在这种情况下,我将添加一个对外界无关紧要的新测试。如何“解决”这个问题?
    • 我认为在 SO 上创建另一个主题会更容易,因为它不仅会得到更多关注,而且(imo)本身就是一个好问题。
    【解决方案4】:

    我不确定您是否应该通过单元测试来测试内部列表或数组大小,因为您无法通过 Stack 接口访问它。实现堆栈的方法有很多,有好有坏,但正如 Bernard 所说,这些都是内部实现。单元测试旨在测试面向外部的功能。

    【讨论】:

      猜你喜欢
      • 2019-01-19
      • 1970-01-01
      • 2011-07-14
      • 2012-04-07
      • 2012-07-27
      • 2011-06-24
      • 1970-01-01
      • 2011-05-12
      相关资源
      最近更新 更多