OCMock:模拟协议未正确停止

时间:2014-02-28 09:17:12

标签: ios unit-testing ocmock sentestingkit

我有一个使用OCMock的测试用例,它执行以下操作:

CAAOAuth2AuthenticationManager *oAuth2AuthManager = [[CAAOAuth2AuthenticationManager alloc] init];
id authDelegate = [OCMockObject mockForProtocol:@protocol(CAAAuthenticationDelegate)];
id partialAuthManagerMock = [OCMockObject partialMockForObject:oAuth2AuthManager];
id resultMock = [OCMockObject mockForClass:[CAAOAuth2AuthenticationResult class]];
[[authDelegate reject] didFailWithError:OCMOCK_ANY];

[[[partialAuthManagerMock expect] andForwardToRealObject] authenticateWithResult:OCMOCK_ANY formData:OCMOCK_ANY delegate:authDelegate];
[[partialAuthManagerMock reject] authenticateWithOptions:OCMOCK_ANY delegate:authDelegate];

[[[resultMock expect] andReturnValue:OCMOCK_VALUE(YES) ] isAuthenticated];
[[resultMock reject] refreshToken];

当我运行测试用例时,同样使用CAAAuthenticationDelegate协议的第二个测试用例(完全不同的测试类和文件)因SIGABRT而失败:

2014-02-28 10:11:24.594 otest[37161:303] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'OCMockObject[CAAAuthenticationDelegate]: unexpected method invoked: didReceiveAuthenticationWithResult:OCMockObject[CAAOAuth2AuthenticationResult] 
stubbed:    didFailWithError:<OCMAnyConstraint: 0xa913fc0>'

但是,我在第二个测试用例中没有使用任何模拟。我试图用stopMocking清除模拟但没有成功。

以下模拟设置可以正常运行:

[[authDelegate reject] didFailWithError:OCMOCK_ANY];

[[[partialAuthManagerMock expect] andForwardToRealObject] authenticateWithResult:OCMOCK_ANY formData:OCMOCK_ANY delegate:authDelegate];
[[partialAuthManagerMock expect] authenticateWithOptions:OCMOCK_ANY delegate:authDelegate];

[[[resultMock expect] andReturnValue:OCMOCK_VALUE(NO) ] isAuthenticated];
[[[resultMock expect] andReturn:refreshToken] refreshToken];

有人可以告诉我,为什么会这样?

2 个答案:

答案 0 :(得分:0)

作为一种解决方法,您可以创建协议的空实现,然后模拟真实对象吗?我用这种方法运气好了 - 模拟协议只会让我感到好奇。

@interface TestAuthDelegateImpl : NSObject <CAAAuthenticationDelegate>
@end
@implementation
- (void)didFailWithError:(id)whatever;
@end

这样的事情。然后只是mockForClass它 - 可能会表现得更好。

答案 1 :(得分:0)

这似乎意味着您的CAAOAuth2AuthenticationManager实例在稍后的测试中仍然存在,并且仍然在其上设置了旧的模拟委托,并且在其上调用了一些方法,这导致调用该委托方法。 CAAOAuth2AuthenticationManager是单例类型的对象,还是第二次测试中使用的相同实例?在第一次测试完成后,我会在auth管理器上将委托重置为nil。

您还可以使用niceMockForProtocol,它将静默忽略任何没有明确拒绝设置的方法调用。除了例外,它听起来已经被删除了,而委托模拟现在只会在发送给它的任何方法上抛出异常,因为也没有预期的设置。

另外,我会在实际调用实际代码时使用STAssertNoThrow()(可能在上面显示的设置之后发生)。拒绝和意外方法将引发异常,这可能导致模拟对象无法正确释放并为后续测试创建问题。如果有问题的测试通过,那可能不是问题。

要检查的最后一件事是你的委托属性是否被声明为“assign”而不是“weak”。如果它是“assign”,并且你没有把它取出并且它被释放,那么任何事情都可能发生(segfault,或者在同一个内存地址分配一个全新的对象)。这似乎也不太可能。