单元测试和私有变量

Unit test and private vars

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

对于 Objective-C,我只添加一个扩展 header。 Swift有没有类似的技巧?请注意,属性 也有一个带有一些代码的 didSet()。

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

没有。在Swift中,私有就是私有。编译器可以使用这个事实来优化,所以根据你如何使用 属性,编译器删除它、内联它或做任何其他会根据实际上在该文件中的代码。 (无论优化器今天是否真的那么聪明,都是允许的。)

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

这是一个 classic 测试问题,classic 测试答案是不要这样测试。不要测试内部状态。如果从外部根本无法判断发生了什么,那么就没有什么可测试的了。重新设计对象,使其可通过其 public 界面进行测试。通常这意味着合成和模拟。

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

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

好的,但是您真的、真的、真的需要它……该怎么做? OK,不破世界也是可以的

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