TDD 单元测试子方法

Posted

技术标签:

【中文标题】TDD 单元测试子方法【英文标题】:TDD Unit Test sub-methods 【发布时间】:2019-06-07 13:36:34 【问题描述】:

我在是否要为重构另一种方法的产物的方法编写测试方面处于两难境地。

第一个问题,考虑这个情节。

class Puzzle(
    val foo: List<Pieces>,
    val bar: List<Pieces>
) 
    init 
       // code to validate foo
       // code to validate bar
    

我在这里验证构造对象的参数。此代码是 TDD 的结果。但是对于 TDD,我们编写 fail_test -&gt; pass test -&gt; refactor,在重构时,我将验证器方法转移到了一个帮助器类 PuzzleHelper

object PuzzleHelper 

    fun validateFoo() 
         ...
    

    fun validateBar() 
         ...
    

在这种情况下我还需要测试validateFoovalidateBar 吗?

第二个问题

class Puzzle(
    val foo: List<Pieces>,
    val bar: List<Pieces>
) 
    ...

    fun getPiece(inPosition: Position) 
        validatePosition()
        // return piece at position
    

    fun removePiece(inPosition: Position) 
        validatePosition()
        // remove piece at position
    


object PuzzleHelper 

    ...

    fun validatePosition() 
         ...
    

我还需要为getPieceremovePiece 编写涉及位置验证的测试吗?

我真的很想熟练使用 TDD,但不知道如何开始。现在我终于潜入,不在乎未来,我想要的只是产品质量。希望尽快听到您的启迪。

【问题讨论】:

How do I test a private function or a class that has private methods, fields or inner classes?的可能重复 嗨@Raedwald,它是那个帖子上关于是否测试私有方法的市场。这部分解决了我的问题。虽然我认为如果我使用 tdd 那么重构结果的方法根本不应该被测试。你同意吗? 如果你所做的只是重构你的代码,那么不需要新的测试,因为所有的代码都已经测试过了。这可以通过更改某些内容并查看测试是否中断来轻松验证。 啊,所以我想我在为验证创建一个辅助类时犯了一个错误,我应该做的是创建一个私有方法。你想写一个答案@Kraylog 吗? 【参考方案1】:

当我们进入Red -&gt; Green -&gt; Refactor 循环的重构阶段时,我们不应该添加任何新行为。这意味着所有代码都已经过测试,因此不需要新的测试。您可以通过更改重构代码轻松验证您是否已完成此操作,并观察它在测试中的失败情况。如果没有,你添加了一些你不应该添加的东西。

在某些情况下,如果提取的代码在其他地方重用,将测试转移到重构代码的测试套件可能是有意义的。

至于第二个问题,这取决于你的设计,以及一些不在你的代码中的东西。例如,如果验证失败,我不知道您想做什么。您必须为这些情况添加不同的测试,以防每种方法的验证失败。

我想指出的一件事是,将方法放置在静态对象(类函数、全局函数,无论你想如何调用它)中会使测试代码变得更加困难。如果您想在忽略验证(将其存根以始终通过)时测试您的类方法,您将无法这样做。 我更喜欢创建一个作为构造函数参数传递给类的协作者。所以你的班级现在得到一个validator: Validator,你可以在测试中通过任何你想要的东西。存根、真实的东西、模拟等等。

【讨论】:

【参考方案2】:

在这种情况下我还需要测试 validateFoo 和 validateBar 吗?

视情况而定。

TDD 的部分意义在于我们应该能够迭代内部设计;又称重构。正是这种魔力让我们能够从对前期设计的少量投资开始,然后在进行中解决剩下的问题——事实上,我们可以改变事物,并且测试评估改变而不会妨碍 em>。

当您的系统所需的行为稳定时,这非常有效。

当系统所需的行为不稳定时,当我们有很多 decisions 不断变化时,当我们知道所需的行为会发生变化但我们没有知道哪个...拥有一个跨越许多不稳定行为的测试往往会使测试变得“脆弱”。

长期以来,这一直是自动化 UI 测试的祸根——因为测试 UI 几乎涵盖了系统每一层的每一个决策,因此测试会不断维护,以消除在面对否则微不足道的行为变化。

在这种情况下,您可能需要开始研究引入隔板的方法,以在需求发生变化时防止过度损坏。我们开始编写测试来验证测试对象的行为与一些更简单的预言机行为的方式相同,同时测试更简单的预言机做正确的事情。

这也是 TDD 反馈循环的一部分——因为跨越许多不稳定行为的测试很困难,我们重构为支持以孤立粒度测试行为的设计,以及就其更简单的元素而言的更大组合。

【讨论】:

以上是关于TDD 单元测试子方法的主要内容,如果未能解决你的问题,请参考以下文章

单元测试和 TDD、OCUnit 与 Google 工具箱

TDD:单元测试异步调用

TDD测试数据加载方法

TDD与单元测试[已结束]

测试驱动开发 (TDD):在 Xcode 4 中编写单元测试

饮食、睡眠和呼吸单元测试/TDD/BDD [关闭]