如何使用OCMock在旧版代码中部分模拟对象? [英] How to partially mock an object inside legacy code with OCMock?

查看:67
本文介绍了如何使用OCMock在旧版代码中部分模拟对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想完成此处所描述的内容,即在旧版代码中创建模拟.但是,我需要 partial 而不是 nice em> strict 模拟.

例如,考虑行为与 GKLeaderbaord ,但实施loadScoresWithCompletionHandler:的存根版本.

我已经在XCTestCase中尝试了此代码,但是当前在运行时在指示的行中失败:OCMInvocationMatcher引发EXC_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 /* ... */ ];

我在做错什么,甚至对于部分模型也有可能吗?

更新现在,我可以看到指示的行可能(显然)如何导致无限递归,但是还不知道如何避免(或中断)它.

更新我也尝试使用OCMStub([leaderboardMock alloc]).andReturn([LeaderboardMock alloc])(也不使用OCMStub([leaderboardMock initWithPlayers: [OCMArg any]]).andReturn([[LeaderboardMock alloc] initWithPlayers:nil]))引入专用的类也没有成功.也许OCMockinit级别上发挥了魔力(文档说: 不可能对init方法进行存根处理,因为它是由模拟本身实现的"),因此alloc(或initWithPlayers:)级别的这种尝试无法达到预期的效果.

解决方案

我现在得出的结论是,方法令人毛骨悚然是一个可能的选择.

一种替换方法可以例如在旧版代码的上下文中生成部分模型,从而在该上下文中引入部分模型,而无需更改旧版API.

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.

解决方案

I have by now concluded that method swizzling would be a possible choice.

A replacement method could e.g. generate a partial mockup from within the context of legacy code and hence introduce a partial mock in that context without requiring changes to legacy APIs.

这篇关于如何使用OCMock在旧版代码中部分模拟对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆