I would like to accomplish what also is described here, i.e create mocks inside legacy code. However I require partial instead of nice or strict mocks.
For example, consider leaderboards that behave exactly like GKLeaderbaord
except for implementing a stubbed version of loadScoresWithCompletionHandler:
.
I've tried this code inside an XCTestCase
but it currently fails at runtime in the indicated line: OCMInvocationMatcher
raises an EXC_BAD_ACCESS
error. Perhaps there is some infinite recursion going on.
id leaderboardMock = OCMClassMock(GKLeaderboard.class);
OCMStub([leaderboardMock alloc])
.andReturn(OCMPartialMock([GKLeaderboard alloc]));
OCMStub([leaderboardMock loadScoresWithCompletionHandler: [OCMArg any]])
.andDo(^(NSInvocation *invocation) { /* ... */ });
// these parts normally nested inside legacy code
GKLeaderboard *leaderboard = /* raises EXC_BAD_ACCESS */
[[GKLeaderboard alloc] initWithPlayers: @[ GKLocalPlayer.localPlayer ]];
leaderboard.identifier = @"Test";
[leaderboard loadScoresWithCompletionHandler: nil /* ... */ ];
What am I doing wrong and is this even possible for partial mockups?
UPDATE I can by now see how the indicated line might (quite obviously) cause an infinite recursion, but don't yet know how to avoid (or break) it.
UPDATE I've also had no success with an attempt of bringing in an dedicated class with OCMStub([leaderboardMock alloc]).andReturn([LeaderboardMock alloc])
(nor with OCMStub([leaderboardMock initWithPlayers: [OCMArg any]]).andReturn([[LeaderboardMock alloc] initWithPlayers:nil])
). Perhaps OCMock
does its magic at the level of init
(the documentation says: "it is not possible to stub the init
method, because that is implemented by the mock itself") hence such an attempt the level of alloc
(or initWithPlayers:
) cannot have its desired effect.
id leaderboardMock = OCMPartialMock(leaderboard);
between its creation and use (between your 1st and 3rd lines of code so to speak). See also here. – Cyclist