Jer*_*emy 36 iphone cocoa-touch objective-c ocmock
我经常在我的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];
}
Run Code Online (Sandbox Code Playgroud)
运行时,我得到:
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).
Run Code Online (Sandbox Code Playgroud)
我很难找到关于此的任何文档,但我认为OCMock不支持类方法.
经过很多谷歌搜索,我发现了这个提示.它有效,但非常麻烦:http: //thom.org.uk/2009/05/09/mocking-class-methods-in-objective-c/
无论如何在OCMock中这样做?或者有人会想到一个聪明的OCMock类别对象可以编写来完成这种事情吗?
Ben*_*ynn 45
OCMock 3的更新
OCMock已经对其语法进行了现代化,以支持类方法存根:
id classMock = OCMClassMock([SomeClass class]);
OCMStub(ClassMethod([classMock aMethod])).andReturn(aValue);
Run Code Online (Sandbox Code Playgroud)
更新
OCMock现在支持开箱即用的类方法存根.OP的代码现在应该按照发布的方式工作.如果存在与类方法同名的实例方法,则语法为:
[[[[mock stub] classMethod] andReturn:aValue] aMethod]
Run Code Online (Sandbox Code Playgroud)
请参阅OCMock的功能.
原始答案
Barry Wark回答后的示例代码.
假类,只是存根connectionWithRequest:委托:
@interface FakeNSURLConnection : NSURLConnection
+ (id)sharedInstance;
+ (void)setSharedInstance:(id)sharedInstance;
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate;
- (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate;
@end
@implementation FakeNSURLConnection
static id _sharedInstance;
+ (id)sharedInstance { if (!_sharedInstance) { _sharedInstance = [self init]; } return _sharedInstance; }
+ (void)setSharedInstance:(id)sharedInstance { _sharedInstance = sharedInstance; }
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate {
return [FakeNSURLConnection.sharedInstance connectionWithRequest:request delegate:delegate];
}
- (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate { return nil; }
@end
Run Code Online (Sandbox Code Playgroud)
切换到模拟:
{
...
// Create the mock and swap it in
id nsurlConnectionMock = [OCMockObject niceMockForClass:FakeNSURLConnection.class];
[FakeNSURLConnection setSharedInstance:nsurlConnectionMock];
Method urlOriginalMethod = class_getClassMethod(NSURLConnection.class, @selector(connectionWithRequest:delegate:));
Method urlNewMethod = class_getClassMethod(FakeNSURLConnection.class, @selector(connectionWithRequest:delegate:));
method_exchangeImplementations(urlOriginalMethod, urlNewMethod);
[[nsurlConnectionMock expect] connectionWithRequest:OCMOCK_ANY delegate:OCMOCK_ANY];
...
// Make the call which will do the connectionWithRequest:delegate call
...
// Verify
[nsurlConnectionMock verify];
// Unmock
method_exchangeImplementations(urlNewMethod, urlOriginalMethod);
}
Run Code Online (Sandbox Code Playgroud)
mha*_*per 17
来自Ruby的世界,我完全理解你想要完成的事情.显然,你真的提前三个小时试图做同样的事情(时区的事情?:-).
无论如何,我认为在OCMock中不需要支持这种方式,因为无论何时,何地或谁调用该方法,存根类方法都需要逐字地进入类并更改其方法实现.这与OCMock似乎所做的相反,它为您提供了一个代理对象,您可以直接操作该代理对象并代替指定类的"真实"对象.
例如,想要存根NSURLConnection + sendSynchronousRequest:returningResponse:error:方法似乎是合理的.但是,通常在我们的代码中使用这个调用有点埋没,因此使它参数化并在NSURLConnection类的模拟对象中交换非常尴尬.
出于这个原因,我认为你发现的"方法调配"方法虽然不够性感,但正是你想要用来存根类方法的.说它非常麻烦似乎极端 - 我们怎么认为它"不优雅",也许不像OCMock为我们生活那么方便.不过,这是一个非常简洁的问题解决方案.
这是一个很好的'要点',有类方法的混合实现:https://gist.github.com/314009
| 归档时间: |
|
| 查看次数: |
19334 次 |
| 最近记录: |