【问题标题】:Unit test and private vars单元测试和私有变量
【发布时间】:2015-04-20 12:12:51
【问题描述】:

我正在为 公共方法 编写 BDD 单元测试。该方法更改了一个私有属性(private var),所以我想编写一个 expect() 并确保它被正确设置。由于它是私有的,我无法弄清楚如何从单元测试目标访问它。

对于 Objective-C,我只需添加一个扩展头。 Swift 中有没有类似的技巧?请注意,该属性还有一个 didSet() 和一些代码。

【问题讨论】:

    标签: unit-testing swift bdd


    【解决方案1】:

    (请注意,Swift 2 添加了@testable 属性,该属性可以使内部方法和属性可用于测试。有关更多信息,请参阅下面的@JeremyP 的 cmets。)

    没有。在 Swift 中,私有就是私有的。编译器可以使用此事实进行优化,因此根据您使用该属性的方式,编译器删除它、内联它或执行任何其他可以根据实际代码给出正确行为的事情是合法的文件。 (无论优化器今天是否真的那么聪明,都是允许的。)

    当然,如果你将你的类声明为@objc,那么你可以打破这些优化,你可以用 ObjC 来查看它。还有一些奇怪的解决方法可以让你使用 Swift 调用任意的@objc 暴露方法(比如零超时NSTimer)。但不要那样做。

    这是一个经典的测试问题,经典的测试答案是不要这样测试。不要测试内部状态。如果实际上不可能从外部判断出发生了什么事,那么就没有什么可测试的了。重新设计对象,使其可通过其公共接口进行测试。通常这意味着组合和模拟。

    这个问题最常见的版本可能是缓存。很难测试是否确实缓存了某些内容,因为唯一的区别可能是检索速度更快。但它仍然可以测试。将缓存功能移动到另一个对象中,并让您的被测对象接受自定义缓存对象。然后,您可以传递一个模拟来记录是否进行了正确的缓存调用(或网络调用、数据库调用或任何内部状态保持)。

    基本上答案是:重新设计,以便更容易测试。

    好的,但你真的,真的,真的需要它……怎么做?好的,不破坏世界也是可能的。

    在要测试的文件中创建一个函数来公开你想要的东西。不是方法。只是一个免费的功能。然后您可以将该辅助函数放入#if TEST,并在您的测试配置中设置TEST。理想情况下,我会让函数实际测试你关心的东西,而不是暴露变量(在这种情况下,也许你可以让函数成为内部甚至公共的)。但无论如何。

    【讨论】:

    • 感谢您的回答。我一直拒绝接受这个作为答案,因为我认为会有更多的选择,但它们都失败了,所以我回到了原点。我希望 Apple 在未来的 Swift 版本中提出更好的方法来处理这个问题。我不喜欢仅仅为了使其可测试而将我的私有类成员包装到另一个对象中。在某些情况下,我最终会得到只拥有一个属性的对象。但我明白你来自哪里。我有一种感觉,许多开发人员会公开属性只是为了懒惰地解决问题。
    • 在 swift 2.0 中不再是这种情况 btw @testable 单元测试属性在为测试而构建时会公开内部方法
    • 这是一个非常好的答案,除了第一句话不是真的。 @testable 不使私有变量可用于测试,只有内部变量。因此,Swift 2 并没有使问题变得微不足道,而且 IMO 有充分的理由。如果无法从外部看到内部状态的影响,谁在乎它是什么?
    • 不是想发起一场激烈的战争,只是为了提供不同的意见——我实际上有点不同意这一点。 IMO 做出一个绝对的陈述就像说测试私有状态或私有方法永远没有用是一种过度概括。
    • (提交得太早)我使用的一种模式(我相信很多人会讨厌这个,但它是一种选择)是不使用实际的私有方法,而是在变量前加上_ 当它们是私有的(就像你在没有私有概念的 python 中所做的那样)。然后你可以测试或不测试它们,因为它是有意义的,仍然有迹象表明它是私有的。
    猜你喜欢
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 2019-09-27
    • 2017-07-23
    • 1970-01-01
    • 2020-06-17
    相关资源
    最近更新 更多