在单元测试中使用不可用的初始值设定项模拟 Cocoa 个对象

Mocking Cocoa objects with unavailable initializers in unit tests

我正在使用 Swift 构建一个 iOS 应用程序,它使用苹果的 CoreBluetooth 框架通过低功耗蓝牙与外围设备通信。为了对实现 CBCentralManagerDelegateCBPeripheralDelegate 协议的自定义控制器进行单元测试,我提供了一个 test double subclass从 CBCentralManager 编辑以模仿 CoreBluetooth API 的行为。在适当的时候调用控制器的委托回调。

到目前为止,这一直运行良好。但是当涉及到调用 CBPeripheralDelegate 回调时,需要传入一个 CBPeripheral 。通常,我会伪造提供我自己的 sub 的组件class 或模拟 CBPeripheral.

的实例

问题所在:底层Objective-C库中CBPeripheral的指定初始值设定项被标记为不可用,这阻止了我从在我伪造的 CBCentralManager 中实例化一个 CBPeripheral 并将其作为参数传递给正在测试的 CBPeripheralDelegate。 (XCode 给我留下编译器错误。)

到目前为止,我已经尝试在我的假子 class 中提供自定义初始化器(这不起作用,因为我最终必须调用不可用的指定初始化),用扩展覆盖初始化器(这是显然不允许)并使用 Objective-C 运行时调用选择器(init),就像我不在乎它不可用一样。最后一种方法似乎是最有前途的,但实际上并没有起作用,并且给我留下了错误类型的非托管对象(我的测试 class)。

我在这里肯定遇到了障碍,非常高兴收到关于

的任何意见
  1. 实例化一个 CBPeripheral 尽管 init() 不可用

  2. 单元测试CBPeripheralDelegate

  3. 的不同方法

我通过追求 objc-runtime 的想法并在 Objective-C 中创建了一个对象工厂,通过它的指针调用初始化程序的实现来忽略不可用标记,从而设法自己解决了这个问题。

更多信息见: http://ijoshsmith.com/2014/06/05/instantiating-classes-by-name-in-swift/ (这在当前 Swift 中不再有效,但可以轻松调整)