我经常在我的iPhone Objective-C单元测试中发现我想要一个类方法,例如NSUrlConnection的sendSynchronousRequest:returningResponse:error:方法 .
简化示例:
- (void)testClassMock
{
id mock = [OCMockObject mockForClass:[NSURLConnection class]];
[[[mock stub] andReturn:nil] sendSynchronousRequest:nil returningResponse:nil error:nil];
}
运行时,我得到:
Test Case '-[WorklistTest testClassMock]' started.
Unknown.m:0: error: -[WorklistTest testClassMock] : *** -[NSProxy doesNotRecognizeSelector:sendSynchronousRequest:returningResponse:error:] called!
Test Case '-[WorklistTest testClassMock]' failed (0.000 seconds).
我很难找到关于此的任何文档,但我认为OCMock不支持类方法 .
经过很多谷歌搜索,我发现了这个提示 . 它有效,但非常麻烦:http://thom.org.uk/2009/05/09/mocking-class-methods-in-objective-c/
无论如何在OCMock中这样做?或者有人会想到一个聪明的OCMock类别对象可以编写来完成这种事情吗?
5 回答
来自Ruby的世界,我完全理解你想要完成的事情 . 显然,你真的提前三个小时试图做同样的事情(时区的事情?:-) .
无论如何,我认为在OCMock中不需要支持这种方式,因为无论何时,何地或谁调用该方法,存根类方法都需要逐字地进入类并更改其方法实现 . 这与OCMock似乎所做的相反,它是为您提供一个代理对象,您可以直接操作该代理对象并代替指定类的"real"对象 .
例如,想要存根NSURLConnection sendSynchronousRequest:returningResponse:error:方法似乎是合理的 . 但是,通常在我们的代码中使用这个调用有点埋没,因此使它参数化并在NSURLConnection类的模拟对象中交换非常尴尬 .
出于这个原因,我认为你非常麻烦的方法看起来非常麻烦 - 我们怎么认同这个问题是一个非常简洁的解决方案 . -1682423_
Update for OCMock 3
OCMock已经对其语法进行了现代化,以支持类方法存根:
Update
OCMock现在支持开箱即用的类方法存根 . OP的代码现在应该按照发布的方式工作 . 如果存在与类方法同名的实例方法,则语法为:
见OCMock's Features .
Original Answer
Barry Wark回答后的示例代码 .
假类,只是存根connectionWithRequest:委托:
切换到模拟:
这是一个很好的'gist',为类方法提供了一个swizzle实现:https://gist.github.com/314009
如果你修改你的测试方法以获取一个注入
NSURLConnection
类的参数,那么's relatively easy to pass in a mock that responds to the given selector (you may have to create a dummy class in your test module which has the selector as an instance method and mock that class). Without this injection, you'使用类方法,基本上使用NSURLConnection
(类)作为单例,因此已经落入使用单例的反模式对象和代码的可测试性受到影响 .链接到问题中的博客帖子和RefuX gist激励我提出阻止他们的想法实现:https://gist.github.com/1038034