如何对我的 NSURLConnection 代理进行单元测试? 我创建了一个 ConnectionDelegate 类,该类遵循不同的协议,以将来自 Web 的数据提供给不同的 ViewControllers。在进一步开始之前,我想先编写单元测试。 但是我不知道如何在没有网络连接的情况下对它们进行单元测试。我还想知道我应该如何处理异步回调。
如何对我的 NSURLConnection 代理进行单元测试? 我创建了一个 ConnectionDelegate 类,该类遵循不同的协议,以将来自 Web 的数据提供给不同的 ViewControllers。在进一步开始之前,我想先编写单元测试。 但是我不知道如何在没有网络连接的情况下对它们进行单元测试。我还想知道我应该如何处理异步回调。
- (NSURLConnection *)newAsynchronousRequest:(NSURLRequest *)request
{
return [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
id objectUnderTest = /* create your object */
id partialMock = [OCMockObject partialMockForObject:objectUnderTest];
NSURLConnection *dummyUrlConnection = [[NSURLConnection alloc]
initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"file:foo"]]
delegate:nil startImmediately:NO];
[[[partialMock stub] andReturn:dummyUrlConnection] newAsynchronousRequest:[OCMArg any]];
[objectUnderTest doRequest];
int statusCode = 200;
id responseMock = [OCMockObject mockForClass:[NSHTTPURLResponse class]];
[[[responseMock stub] andReturnValue:OCMOCK_VALUE(statusCode)] statusCode];
[objectUnderTest connection:dummyUrlConnection didReceiveResponse:responseMock];
NSData *responseData = [RESPONSE_TEXT dataUsingEncoding:NSASCIIStringEncoding];
[objectUnderTest connection:dummyUrlConnection didReceiveData:responseData];
[objectUnderTest connectionDidFinishLoading:dummyUrlConnection];
编辑(2014年2月18日):我刚刚偶然发现了这篇文章,它提供了一种更优雅的解决方案。
http://www.infinite-loop.dk/blog/2011/04/unittesting-asynchronous-network-access/
基本上,你需要以下方法:
- (BOOL)waitForCompletion:(NSTimeInterval)timeoutSecs {
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
if([timeoutDate timeIntervalSinceNow] < 0.0)
break;
} while (!done);
return done;
}
STAssertTrue([self waitForCompletion:5.0], @"Timeout");
基本格式:
- (void)testAsync
{
// 1. Call method which executes something asynchronously
[obj doAsyncOnSuccess:^(id result) {
STAssertNotNil(result);
done = YES;
}
onError:^(NSError *error) [
STFail();
done = YES;
}
// 2. Determine timeout
STAssertTrue([self waitForCompletion:5.0], @"Timeout");
}
==============
我来晚了,但是我找到了一个非常简单的解决方案。(感谢http://www.cocoabuilder.com/archive/xcode/247124-asynchronous-unit-testing.html)
.h文件:
@property (nonatomic) BOOL isDone;
.m文件:
- (void)testAsynchronousMethod
{
// 1. call method which executes something asynchronously.
// 2. let the run loop do its thing and wait until self.isDone == YES
self.isDone = NO;
NSDate *untilDate;
while (!self.isDone)
{
untilDate = [NSDate dateWithTimeIntervalSinceNow:1.0]
[[NSRunLoop currentRunLoop] runUntilDate:untilDate];
NSLog(@"Polling...");
}
// 3. test what you want to test
}
isDone
在执行异步方法的线程中被设置为 YES
。
因此,在这种情况下,我在步骤1中创建并启动了 NSURLConnection,并将其委托给了这个测试类。在
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
中,我设置了 self.isDone = YES;
。我们跳出 while 循环,测试已执行完成。完成。
在单元测试中,我避免使用网络。取而代之的是:
然后我专注于更有趣的部分:合成具有各种特征的模拟 NSURLResponses,并将它们传递给 NSURLConnectionDelegate 方法。
-setup
方法中注册测试协议,并在您的-tearDown
方法中取消注册。这是我的做法:
~/Sites
文件夹中,放置一个测试文件(任何数据都可以,我们称之为myfile.test
)。