Unit testing 单元测试和专用VAR

Unit testing 单元测试和专用VAR,unit-testing,swift,bdd,Unit Testing,Swift,Bdd,我正在为一个公共方法编写一个BDD单元测试。该方法更改了一个私有属性(private var),因此我想编写一个expect(),并确保它设置正确。由于它是私有的,我无法确定如何从单元测试目标访问它 对于Objective-C,我只需要添加一个扩展标题。斯威夫特有类似的技巧吗?请注意,该属性有一个didSet(),其中还包含一些代码。(请注意,Swift 2添加了@testable属性,该属性可以使内部方法和属性可用于测试。有关更多信息,请参阅下面的@JeremyP注释。) 不,在斯威夫特,私人

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

对于Objective-C,我只需要添加一个扩展标题。斯威夫特有类似的技巧吗?请注意,该属性有一个didSet(),其中还包含一些代码。

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

不,在斯威夫特,私人就是私人。编译器可以使用此事实进行优化,因此根据您使用该属性的方式,编译器删除、内联该属性或执行任何其他操作都是合法的,这些操作将根据该文件中实际的代码提供正确的行为。(无论优化器今天是否真的那么聪明,都是允许的。)

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

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

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

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

好的,但是你真的,真的,真的需要它。。。怎么做?好吧,这是可能的,而不打破世界


在要测试的文件中创建一个函数,该函数公开您想要的内容。不是一种方法。只是一个自由函数。然后,您可以将该助手函数放入
#if TEST
,并在测试配置中设置
TEST
。理想情况下,我会让函数实际测试您关心的事情,而不是公开变量(在这种情况下,也许您可以让函数是内部的,甚至是公共的)。但不管怎样。

谢谢你的回答。我一直推迟接受这个答案,因为我认为还有一些选择,但都失败了,所以我回到了原点。我希望苹果能在未来版本的Swift中想出更好的方法来处理这个问题。我不太喜欢为了使私有类成员可测试而将其包装到另一个对象中。在某些情况下,我最终会得到只包含一个属性的对象。但我知道你来自哪里。我有一种感觉,许多开发人员会公开属性,只是为了懒散地解决这个问题。在swift 2.0 btw@testable单元测试属性中不再是这种情况,而是在构建用于测试的内部方法时公开。这是一个非常好的答案,除了第一句不是真的
@testable
不提供用于测试的专用变量,仅提供内部变量。因此,Swift 2并没有让问题变得微不足道,在我看来,这是有充分理由的。如果无法从外部看到内部状态的影响,谁会在乎它是什么呢?不是试图发动一场火焰战,只是提供一个不同的观点——我实际上不同意这一点。在我看来,做一个绝对的陈述,比如说测试私有状态或私有方法从来没有用,这是一种过度概括。(提交得太早了)我使用过的一种模式(我相信很多人会讨厌这个,但这是一种选择)是不使用实际的私有方法,相反,当变量应该是私有的时(就像python中没有私有概念的情况一样),在变量前面加上
。然后,你可以测试或不测试它们,因为这是有意义的,而且仍然有迹象表明它是私有的。