我正在为一个公共方法写一个BDD单元测试。该方法更改了一个私有属性(private var),所以我想写一个expect(),并确保它正确设置。因为它是私有的,我不能解决如何从单元测试目标访问它。
对于Objective-C,我只是添加一个扩展标题。 Swift中有类似的技巧吗?注意,属性有一个didSet()与一些代码。
(请注意,Swift 2添加了可以使内部方法和属性可用于测试的@testable属性。有关更多信息,请参阅@ JeremyP的注释。
在Swift中,私人是私人的。编译器可以使用这个事实进行优化,所以根据你使用该属性的方式,编译器删除它,内联它,或做任何其他事情,这将是基于代码实际上正确的行为是合法的文件。 (无论优化器是否实际上是聪明的今天或不,它是允许的。)
现在当然如果你声明你的类是@objc,那么你可以打破这些优化,你可以去探讨ObjC阅读它。还有一些奇怪的解决方法,可以让你使用Swift调用任意@objc暴露方法(如零超时NSTimer)。但不要这样做。
这是一个经典的测试问题,经典的测试答案是不要这样测试。不要测试内部状态。如果根本不可能从外面告诉发生了什么事情,那么没有什么可以测试。重新设计对象,使其可以通过其公共接口进行测试。通常这意味着组成和嘲笑。
这个问题的最常见的版本可能是缓存。很难测试某些东西是否被实际缓存,因为唯一的区别可能是它被更快地检索。但它仍然可以测试。将缓存功能移动到另一个对象,并让您的测试对象接受自定义缓存对象。然后您可以传递一个模拟,记录是否进行了正确的缓存调用(或网络调用或数据库调用,或任何内部状态持有)。
基本上,答案是:重新设计,使其更容易测试。
OK,但你真的,真的,真的需要它…如何做呢?好的,这是可能没有打破世界。
在要测试的文件中创建一个暴露你想要的东西的函数。不是一种方法。只是一个自由的功能。然后,您可以将该帮助函数放在#if TEST中,并在测试配置中设置TEST。理想情况下,我会让函数实际测试你关心的事情,而不是暴露变量(在这种情况下,也许你可以让函数是内部的,甚至是公共的)。但是无论哪种方式。