2015-01-30 4 views
0

나는 또한 here으로 묘사 된 것을 달성하고 싶습니다. 즉 레거시 코드 내에 모의 객체를 만듭니다. 그러나 나는 대신 partial이 필요합니다.or strict 가짜입니다.레거시 코드에서 OCMock으로 개체를 부분적으로 조롱하는 방법은 무엇입니까?

예를 들어 loadScoresWithCompletionHandler:의 스터브 버전을 구현하는 경우를 제외하고 정확히 GKLeaderbaord과 같은 동작을하는 리더 보드를 고려해보십시오.

나는이 코드를 XCTestCase 안에 시도했지만 현재 런타임에 표시된 줄에 오류가 발생했습니다. OCMInvocationMatcherEXC_BAD_ACCESS 오류를 발생시킵니다. 아마도 무한 재귀가 진행 중일 것입니다.

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 /* ... */ ]; 

무엇이 잘못 되었나요? 그리고 부분 모형을 만들 수 있습니까? 지금 쯤

UPDATE 내가 할 수있는이 표시된 라인 (아주 명백하게) 무한 재귀가 발생할 수 있습니다 방법을 볼 수 있지만, 아직 그것을 피할 방법을 알고 (또는 중단)하지 않습니다.

UPDATE는 또한 OCMStub([leaderboardMock alloc]).andReturn([LeaderboardMock alloc])와 (나 OCMStub([leaderboardMock initWithPlayers: [OCMArg any]]).andReturn([[LeaderboardMock alloc] initWithPlayers:nil])있는) 전용 클래스에서 가져 오는 시도 어떠한 성공을 했어. 아마도 OCMockinit의 레벨에서 마법을 실행합니다 (documentation은 "init 메서드를 스텁하는 것은 불가능합니다. 모의 자체로 구현되기 때문에") 따라서 이러한 시도는 alloc (또는 initWithPlayers:) 레벨에는 가질 수 없습니다. 원하는 효과.

답변

0

method swizzling이 가능한 선택이 될 것입니다 결론을 내렸다.

교체 방법은 예를 들어. 레거시 코드의 컨텍스트 내에서 부분 모형을 생성하고 따라서 레거시 API를 변경하지 않고 해당 컨텍스트에서 부분 모의를 도입 할 수 있습니다.

0

나는 당신이하려는 것을 잘 모릅니다. 그것은 오해처럼 보입니다. 다음 사항이 효과가 없습니까?

GKLeaderboard *leaderboard = [[GKLeaderboard alloc] initWithPlayers: ... ]; 
id leaderboardMock = OCMPartialMock(leaderboard); 
OCMStub([leaderboarMock loadScoresWithCompletionHandler: ...]); 

일반 개체를 제한없이 사용할 수 있습니다. 객체에 대해 생성 된 부분 모의 객체를 사용하여 leaderboard에있는 실제 인스턴스를 조작 할 수 있습니다. 그것은 부분적 모의의 아름다움입니다.

UPDATE : 객체 생성이 통제하지 않으면, 다음 시도 할 수 있습니다 : 지금 쯤은 내가 가진

GKLeaderboard *leaderboard = [[GKLeaderboard alloc] initWithPlayers: ... ]; 
id leaderboardMock = OCMPartialMock(leaderboard); 

OCMStub([leaderboardMock alloc]).andReturn(leaderboardMock); 
OCMStub([leaderboardMock initWithPlayers:[OCMArg any]).andReturn(leaderboard); 

OCMStub([leaderboarMock loadScoresWithCompletionHandler: ...]); 
+0

문제는 (내가 지금 그것을 인식으로) 리더는 내가 건드릴 수 없어 레거시 코드에 깊은 만든 것입니다. 그러므로 나는 그것의 생성과 사용 사이 ('id leaderboardMock = OCMPartialMock (leaderboard); ')에 전화를 걸 수있는 방법이 없다. [here] (http://stackoverflow.com/q/18503604/1789384)도 참조하십시오. – Drux

+0

'init' 메소드를 조롱 할 수는 없지만'initWithPlayers :'가 작동해야합니다. 그래서 alloc/init 조롱을 시도해보십시오. –

+0

'OCMPartialMock' ('OCMClassMock'과 반대)을 호출하려면'leaderboard'의 인스턴스를 알아야합니다. 불행히도, 그것은 단지 레거시 코드베이스 내부에서 생성 된 후에 알려지며 일부 API에 노출되지 않습니다. – Drux

0

다음 줄을 사용하면 안됩니다. 전체 클래스를 모의 해보고 실제 개체가 호출되지 않습니다.

OCMClassMock (GKLeaderboard.class)