【问题标题】:CLLocationManagerDelegate mocking on users denialCLLocationManagerDelegate 嘲笑用户拒绝
【发布时间】:2023-04-05 13:30:01
【问题描述】:

-- 最终编辑: 更准确的问题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 预期:locationManager:didFailWithError:'

所以我以为我明白了,并在我的 delegateTarget 对 didFailWithError 的期望之前添加了下面的代码

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

结果是:

名称:NSInternalInconsistencyException 文件:未知 线路:未知 原因:OCMockObject[CLLocationManagerDelegate]:未调用 2 个预期方法: 位置管理器: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 预期:locationManager:OCPartialMockObject[CLLocationManager] didChangeAuthorizationStatus:2 预期:locationManager:OCPartialMockObject[CLLocationManager] didFailWithError:'

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

-- 最终编辑: 更准确的问题Unit Test CLLocationManager implementation

【问题讨论】:

标签: ios unit-testing ocmock


【解决方案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,您将真正了解一些后台的工作原理。

编辑:

就我个人而言,我不知道您真正想测试什么。苹果框架?您的类/协议中没有任何实体。你在测试什么?

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

期望调用 ViewControllers 委托方法。如果您的位置经理是单身人士,那么 it's a bit tricky to replace it 带有假/存根。

【讨论】:

  • 感谢您的回答,这是我在编辑中的第一次尝试,但我不得不更改它,因为它不起作用。请参阅我的问题编辑。
  • 如果您期望 [OCMArg any] 而不是 trueLocationManagerlocationManager 会发生什么?
  • 替换为 [OCMArg any] 并不能解决问题。最初我想要测试处理 CLLocationManager 的类。我想测试当用户拒绝地理定位时调用了哪些方法。也许我应该重新打开另一个问题并删除这个不够准确的问题。
  • 也许这是一个更准确的问题stackoverflow.com/questions/20376000/…
【解决方案2】:

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

【讨论】:

  • 事实上,最初我试图测试我对 CLLocationManager 和 CLLocationManagerDelegate 响应的封装,但也找不到有效的解决方案,所以我在我的测试用例中返回直接测试 CLLocationManager(因此我的问题)。关于您的回答,我用几个代码假设编辑了我的初始问题。感谢您的宝贵时间。
猜你喜欢
  • 2020-12-14
  • 1970-01-01
  • 2014-10-27
  • 2016-10-02
  • 2019-12-20
  • 1970-01-01
  • 2019-01-02
  • 2019-02-15
  • 2010-09-23
相关资源
最近更新 更多