在Xcode 5.0中不能用OCMock 2.1+存储类方法

我知道,OCMock版本2.1+ 支持开箱即用的类别方法。 但由于某种原因,它不适合我。 为了确保我将问题隔离开来,我简单地克隆了示例OCMock项目 (清楚地标记为版本2.2.1),并简单地将其添加到testMasterViewControllerDeletesItemsFromTableView中 :

id detailViewMock = [OCMockObject mockForClass:[DetailViewController class]]; [[[detailViewMock stub] andReturn:@"hello"] helloWorld]; 

DetailViewController.h我补充说:

 + (NSString *)helloWorld; 

DetailViewController.m

 + (NSString *)helloWorld { return @"hello world"; } 

但是我一直在得到这个错误:

 *** -[NSProxy doesNotRecognize Selector:helloWorld] called! 

看到这个问题的演示,请克隆这个回购看看是怎么回事。

这应该工作得很好。 我只是在Xcode5上使用XCTest的一个项目中试过,而且代码已经通过了。

我会1)确保你正在使用最新版本的OCMock(现在是2.2.1;我认为在新版本中对于类方法和Xcode5都有一些修复),2)确保你的DetailViewController类是正确地链接到运行时(即正确目标的一部分)。

在查看您的项目时,您的DetailViewController类是主应用程序testing目标的一部分。 使用Xcode5,看起来这意味着类的两个副本被编译并存在于运行时,应用程序中的代码调用一个副本,testing用例中的代码调用另一个副本。 这曾经是一个链接器错误(重复的符号),但无论好坏,链接器现在似乎默默地允许ObjC运行时中存在相同类的两个副本(具有相同的名称)。 OCMock使用dynamic查找find第一个(编译到应用程序中的),但是testing用例直接链接到第二个副本(编译到testing包的副本)。 所以…… OCMock实际上并不是在嘲笑你认为的类。

通过validation[DetailViewController类]不等于NSClassFromString(@“DetailViewController”)(第一个是直接链接的,第二个是dynamic的)的部分testing用例,你可以看到这一点。

要正确解决这个问题,在DetailViewController.m的“目标成员”中,只需取消选中testing目标。 这样在运行时只有一个类的副本,事情就像你期望的那样工作。 testing包被加载到主应用程序中,所以主应用程序的所有类都可以使用到包中,而不必直接将它们编译到包中。 类只应该是两个目标之一的一部分,而不是两个(这一直是这种情况)。

你能显示你正在testing的代码吗? 这工作:

 @interface DetailViewController : UIViewController + (NSString *) helloWorld; @end @implementation DetailViewController + (NSString *)helloWorld { return @"hello world"; } @end 

考试:

 - (void) test__stubbing_a_class_method { id mockDetailViewController = [OCMockObject mockForClass:[DetailViewController class]]; [[[mockDetailViewController stub] andReturn:@"hello"] helloWorld]; STAssertEqualObjects([DetailViewController helloWorld], @"hello", nil); } 

看看你的示例项目:

  1. 您不应该在您的testing目标中编译DetailViewController.m。

  2. 你不应该在你的主要目标中引用OCMock。

我从两个项目中删除了所有对OCMock的引用,然后从源代码包含了OCMock,testing通过的很好。 我想你可能只是有一些环境冲突导致你的问题。

尽pipe卡尔·林德伯格的回答是正确的 ,但我想我会在这里回答他的评论:

  • 问题就在于我使用的是过时的OCMock版本。 我到达那里的原因是B / C的ocmock页面上的说明只是简单地引用我从他们的github帐户抓取iOS示例,并复制OCMock库(他们甚至指示使用相同的目录结构)。 事实certificate,他们的例子中的图书馆是2岁以上! 。

  • 要解决这个问题,只需在shell中运行build.rb脚本就可以了: ruby build.rb 。 这将给你一个最新的libOCMock.a库,你可以简单地插回到你的项目,瞧! 一切都完成了!

只是使用

 id detailViewMock = [OCMockObject niceMockForClass:[DetailViewController class]];