OCMock,为啥我不能期望协议上的方法?

Posted

技术标签:

【中文标题】OCMock,为啥我不能期望协议上的方法?【英文标题】:OCMock, why can't I expect method on a protocol?OCMock,为什么我不能期望协议上的方法? 【发布时间】:2012-09-27 09:34:15 【问题描述】:

考虑一下这段代码,它可以工作(loginWithEmail 方法正如预期的那样):

_authenticationService = [[OCMockObject mockForClass:[AuthenticationService class]] retain];
[[_authenticationService expect] loginWithEmail:[OCMArg any] andPassword:[OCMArg any]];

对比这段代码:

_authenticationService = [[OCMockObject mockForProtocol:@protocol(AuthenticationServiceProtocol)] retain];
[[_authenticationService expect] loginWithEmail:[OCMArg any] andPassword:[OCMArg any]];

第二个代码示例在第 2 行失败,出现以下错误:

*** -[NSProxy doesNotRecognizeSelector:loginWithEmail:andPassword:] called! Unknown.m:0: error: -[MigratorTest methodRedacted] : ***
-[NSProxy doesNotRecognizeSelector:loginWithEmail:andPassword:] called!

AuthenticationServiceProtocol 声明方法:

@protocol AuthenticationServiceProtocol <NSObject>
@property (nonatomic, retain) id<AuthenticationDelegate> authenticationDelegate;

- (void)loginWithEmail:(NSString *)email andPassword:(NSString *)password;
- (void)logout;
- (void)refreshToken;

@end

并且在类中实现:

@interface AuthenticationService : NSObject <AuthenticationServiceProtocol>

这是在 ios 上使用 OCMock。

当模拟是mockForProtocol 时,为什么expect会失败?

【问题讨论】:

您是从源代码构建 OCMock 吗?在OCProtocolMockObjectmethodSignatureForSelector: 方法中放置一个断点会很有趣。 不是从源代码构建,只是下载了静态库。 你能发布实际的协议声明吗? 是的,刚刚编辑了问题以包含正在使用的完整的实际协议。 【参考方案1】:

这很奇怪。我在 iOS5 示例项目中添加了以下类:

@protocol AuthenticationServiceProtocol

- (void)loginWithEmail:(NSString *)email andPassword:(NSString *)password;

@end

@interface Foo : NSObject

    id<AuthenticationServiceProtocol> authService;


- (id)initWithAuthenticationService:(id<AuthenticationServiceProtocol>)anAuthService;
- (void)doStuff;

@end

@implementation Foo

- (id)initWithAuthenticationService:(id<AuthenticationServiceProtocol>)anAuthService

    self = [super init];
    authService = anAuthService;
    return self;


- (void)doStuff

    [authService loginWithEmail:@"x" andPassword:@"y"];


@end

@implementation ProtocolTests

- (void)testTheProtocol

    id authService = [OCMockObject mockForProtocol:@protocol(AuthenticationServiceProtocol)];
    id foo = [[Foo alloc] initWithAuthenticationService:authService];

    [[authService expect] loginWithEmail:[OCMArg any] andPassword:[OCMArg any]];

    [foo doStuff];

    [authService verify];


@end

当我在 Xcode 版本 4.5 (4G182) 中针对 iPhone 6.0 模拟器运行此测试时,测试通过了。模拟对象的使用方式有什么不同吗?在您的情况下, _authenticationService 传递到哪里?收件人对它做了什么?

【讨论】:

您好,埃里克,感谢您的回答。我试图在一个单独的空测试项目中重现这一点,但我不能,所以我必须调查究竟是什么触发了这种行为。如果我找到任何东西,我会回复你。仅供参考,错误发生在 expect 调用上,然后将模拟传递给我的任何被测代码。 @driis 我也尝试复制它,但不能。您使用的是哪个版本的 OCMock? @Erik 我们如何在委托方法调用期间获取传递的参数?和上面的例子一样,doStuff 方法调用 authService 方法,参数为 @"x" 和 @"y"。如何在测试用例中读取 @"x" 和 @"y"? @iVishal 无关。请打开一个新问题。 我有同样的问题,我也无法在我的项目之外重现这个问题。我打开了github.com/erikdoe/ocmock/issues/78,但是用处不大。

以上是关于OCMock,为啥我不能期望协议上的方法?的主要内容,如果未能解决你的问题,请参考以下文章

使用 OCMock 模拟块期望

为啥我不能直接将 int 或 bool 传递给 OCMock 的“andReturnValue”参数?

为啥 classifier.predict() 方法期望测试数据中的特征数量与训练数据中的相同?

为啥 WCF 会返回 myObject[] 而不是 List<T> 像我期望的那样?

为啥这个钻石类继承输出不是我期望的?

为啥 SQL 查询的结果没有按我期望的顺序返回?