一个单元如何测试与核心蓝牙 API 交互的代码?

Mic*_*ire 6 unit-testing objective-c core-bluetooth ocmockito kiwi

我想单元测试充当一个类CBPeripheralManagerDelegateCBPeripheralManager类。通常,为了排除外部类依赖项,我会使用一种形式的依赖项注入,通过类初始值设定项或通过属性传入。在处理基于单例的 API 时,我已经能够使用像 Kiwi 这样的库来存根返回单例的类级方法(即[ClassName stub:@selector(sharedInstance) andReturn:myStubbedInstance])。模拟情况下的问题CBPeripheralManager是它的初始值设定项采用委托实例。所以任何使用我的类的代码都需要做这样的事情:

PeripheralManagerWrapper *wrapper = [[PeripheralManagerWrapper alloc] init];
CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:wrapper queue:nil options:nil];
wrapper.peripheralManager = peripheralManager;
Run Code Online (Sandbox Code Playgroud)

然后,为了对我的PeripheralManagerWrapper类进行单元测试,我可以简单地实例化它并传入一个模拟的CBPeripheralManager. 但是,我不喜欢要求我的包装器对象的任何调用代码都必须经过此设置。有没有更好的模式来处理这种情况?我已经使用了 Kiwi 和 OCMockito,但似乎都没有提供这个功能,除非可能存根allocinit方法,CBPeripheralManager然后只是在PeripheralManagerWrapper 的初始化程序中实例化实例。

all*_*rog 4

恕我直言,核心蓝牙 API 非常适合单元测试。所有委托回调都采用管理器和相关参数,因此如果您遵循使用这些参数而不是内部状态的模式,那么您将能够传递您想要的任何内容。使用模拟对象是实现此目的的最佳方法。在单元测试时,您不应该试图嘲笑经理的行为。您应该专注于验证代码与 API 的交互,仅此而已。

包装器可能更适合集成测试。但实际上,根据我的经验,核心蓝牙代码的集成测试最好手动完成。堆栈不够稳定,无法进行可靠的测试,并且测试代码也必须针对堆栈错误进行强化,这确实很困难,因为显然,仅通过查看 API 无法记录或预测这些错误。另一方面,您的测试代码也必须模拟堆栈的错误行为。在某些情况下,这是可能的,但测试代码即使不比您正在测试的代码更复杂,也将同样复杂。