CLLocationManagerDelegate模拟用户拒绝

时间:2013-12-03 10:07:54

标签: ios unit-testing ocmock

- 最终修改: 更准确的问题Unit Test CLLocationManager implementation

我正在尝试模拟CLLocationManagerDelegate来处理拒绝进行地理定位的用户

id locationManager = [OCMockObject niceMockForClass:[CLLocationManager class]];
[[[locationManager stub] andReturnValue:@(kCLAuthorizationStatusDenied)] authorizationStatus];

id delegateTarget = [OCMockObject niceMockForProtocol:@protocol(CLLocationManagerDelegate)];
[[delegateTarget expect] locationManager:locationManager didFailWithError:[OCMArg any]];

[locationManager setDelegate:delegateTarget];
[locationManager startUpdatingLocation];

[delegateTarget verify];

但是这段代码不起作用,我一直收到这个错误:

  

名称:NSInternalInconsistencyException       档案:未知       行:未知       原因:OCMockObject [CLLocationManagerDelegate]:未调用预期方法:locationManager:OCMockObject [CLLocationManager] didFailWithError:

如何确保调用CLLocationManagerDelegate方法locationManager:didFailWithError:?

编辑: 如果我为我的CLLocationManager实例使用partialMock而不是niceMock:

CLLocationManager *trueLocationManager = [[CLLocationManager alloc] init];
id locationManager = [OCMockObject partialMockForObject:trueLocationManager];
[[[locationManager stub] andReturnValue:@(kCLAuthorizationStatusDenied)] authorizationStatus];

id delegateTarget = [OCMockObject mockForProtocol:@protocol(CLLocationManagerDelegate)];
[[delegateTarget expect] locationManager:trueLocationManager didFailWithError:[OCMArg any]];

[locationManager setDelegate:delegateTarget];
[locationManager startUpdatingLocation];

[delegateTarget verify];

我明白了:

  

由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'OCMockObject [CLLocationManagerDelegate]:调用了意外的方法:locationManager:didChangeAuthorizationStatus:2       expected:locationManager:didFailWithError:'

所以我想我得到了它并在我的delegateTarget期望didFailWithError之前添加了下面的代码

[[delegateTarget expect] locationManager:trueLocationManager didChangeAuthorizationStatus:2]; // kCLAuthorizationStatusDenied = 2

结果是:

  

名称:NSInternalInconsistencyException       档案:未知       行:未知       原因:OCMockObject [CLLocationManagerDelegate]:未调用2个预期方法:           locationManager:didChangeAuthorizationStatus:2           locationManager:didFailWithError:

真的不知道我做错了什么......

Edit2:对于Ilea Cristian

CLLocationManager *trueLocationManager = [[CLLocationManager alloc] init];
id locationManager = [OCMockObject partialMockForObject:trueLocationManager];
[[[locationManager stub] andReturnValue:@(kCLAuthorizationStatusDenied)] authorizationStatus];

id delegateTarget = [OCMockObject mockForProtocol:@protocol(CLLocationManagerDelegate)];
[[delegateTarget expect] locationManager:locationManager didChangeAuthorizationStatus:2]; // kCLAuthorizationStatusDenied = 2
[[delegateTarget expect] locationManager:locationManager didFailWithError:[OCMArg any]];

[locationManager setDelegate:delegateTarget];
[locationManager startUpdatingLocation];

[delegateTarget verify];

我明白了:

  

由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'OCMockObject [CLLocationManagerDelegate]:调用了意外的方法:locationManager:didChangeAuthorizationStatus:2       expected:locationManager:OCPartialMockObject [CLLocationManager] didChangeAuthorizationStatus:2       expected:locationManager:OCPartialMockObject [CLLocationManager] didFailWithError:'

看起来在委托回调中使用的locationManager是trueLocationManager而不是locationManager(partialMock)

- 最终修改: 更准确的问题Unit Test CLLocationManager implementation

2 个答案:

答案 0 :(得分:1)

你有这一行:

[locationManager setDelegate:delegateTarget];

这意味着当调用locationManager:didFailWithError:时,为CLLocationManager参数传递的对象将是名为locationManager的OCMock对象 - 而不是trueLocationManager

您的期望:

[[delegateTarget expect] locationManager:trueLocationManager didFailWithError:[OCMArg any]];

所以,你期望一个通过trueLocationManager的调用,而是传递部分模拟。尝试期望传递部分模拟。

OCMock部分模拟,如locationManager,只是真实对象的代理包装,但它们的类型不同(这就是你使用id而不是真实类型的原因)。

由于Objective-C通过消息传递处理调用的方式,这种魔法起作用。如果您仔细阅读NSProxy,然后查看OCMock implementation,您将真正了解一些后台工作的效果。

编辑:

就我个人而言,我不知道你真正想要测试什么。 Apple框架?这些实体都没有您的类/协议。你在测试什么?

我猜你有一个实现CLLocationManagerDelegate协议的ViewController。嘲笑那个班。如果您的位置管理器是属性,则将其存根以返回您的虚假位置管理器(以便vc内部使用虚假的)。或者将假冒的locationManager.delegate设置为您的ViewController。启动假位置管理器。

期望ViewControllers委托方法被调用。如果您的位置管理员是单身人士,则it's a bit tricky to replace it使用假/存根。

答案 1 :(得分:0)

您已为LocationManager创建了“漂亮的模拟”。这意味着您将默默忽略对setDelegate:startUpdatingLocation的来电。您可以将其切换为部分模拟,但您只是在测试LocationManager吗?您应该只需要测试位置管理器委托的实现 - 您可以直接调用这些委托方法。