8

Consider this code, which works (the loginWithEmail method gets expected as, well, expected):

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

Versus this code:

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

The second code example fails on line 2 with the following error:

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

AuthenticationServiceProtocol declares the method:

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

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

@end

And it is implemented in the class:

@interface AuthenticationService : NSObject <AuthenticationServiceProtocol>

This is using OCMock for iOS.

Why does expectfail when the mock is a mockForProtocol?

driis
  • 161,458
  • 45
  • 265
  • 341

1 Answers1

2

This is curious. I have added the following class into the iOS5 example project:

@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

When I run this in Xcode Version 4.5 (4G182) against the iPhone 6.0 Simulator the test passes. Is there any difference in how the mock object is used? In your case, where does _authenticationService get passed to? What is the recipient doing to it?

Erik Doernenburg
  • 2,933
  • 18
  • 21
  • Hi Erik, thanks for your answer. I have tried to reproduce this in a separate empty test project, and I can't, so I will have to investigate exactly what triggers the behaviour. I will get back to you if I find anything. FYI, the error occurs on the `expect` call, before the mock is passed to any of my code under test. – driis Sep 28 '12 at 07:57
  • @driis I tried to reproduce it as well but couldn't. Which version of OCMock are you using? – g_fred Sep 28 '12 at 11:10
  • @Erik How can we get the argument passed during delegate method call?? Like in above case, doStuff method is calling authService method with arguments @"x" and @"y". How can I read @"x" and @"y" in test case? – Vishal Singh Apr 02 '14 at 06:35
  • @iVishal Unrelated. Please open a new question. – Erik Doernenburg Apr 05 '14 at 14:51
  • I have the same issue, and I also can't reproduce this outside of my project. I opened https://github.com/erikdoe/ocmock/issues/78, but it's not very useful. – Eduardo Scoz May 01 '14 at 16:37