cocoa - OCMock 异步 block 回调

标签 cocoa unit-testing objective-c-blocks ocmock

我正在构建一个小型库来为我处理文件上传和下载操作,并尝试将一套测试集成到其中。我没有使用委托(delegate)回调方法,而是在完成处理程序 block 中处理异步响应,如下所示:

  SyncKit *engine = [[SyncKit alloc] init];
  NSURL *localFilePath = [NSURL URLWithString:@"/Users/justin/Desktop/FileTest.png"];

  [engine uploadFileWithFilename:@"FileTest.png" toRemotePath:@"/" fromLocalPath:localFilePath withCompletionHandler:^(id response, NSError *error) {
    if (error)
    {
      NSLog(@"error = %@", error);
      return;
    }

    NSLog(@"File uploaded and return JSON response = %@", response);
  }];  

底层的uploadFileWithFilename...方法如下:

- (void)uploadFileWithFilename:(NSString *)filename toRemotePath:(NSString *)remotePath fromLocalPath:(NSURL *)localPath withCompletionHandler:(SKCompletionHandler)handler
{
  if ((![[NSFileManager defaultManager] fileExistsAtPath:[localPath path]]))
  {
    NSDictionary *userInfo = [NSDictionary dictionaryWithObject:localPath forKey:@"localPath"];
    NSError *error = [NSError errorWithDomain:SKDropboxErrorDomain code:SKDropboxErrorFileNotFound userInfo:userInfo];
    handler(nil, error);
    return;
  }

  // path is the directory the file will be uploaded to, make sure it doesn't have a trailing /
  // (unless it's the root dir) and is properly escaped
  NSString *trimmedPath;
  if (([remotePath length] > 1) && ([remotePath characterAtIndex:[remotePath length] - 1] == '/')) 
  {
    trimmedPath = [remotePath substringToIndex:[remotePath length] - 1];
  } 
  else if ([remotePath isEqualToString:@"/"])
  {
    trimmedPath = @"//";
  }
  else 
  {
    trimmedPath = remotePath;
  }

  NSString *escapedPath = [NSString escapePath:trimmedPath];
  NSString *fullPath = [NSString stringWithFormat:@"/files/dropbox%@", escapedPath];      
  NSString *urlString = [NSString stringWithFormat:@"%@://%@/%@%@", kSKProtocolHTTPS, kSKDropboxAPIContentHost, kSKDropboxAPIVersion, fullPath];

  NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:filename, @"file", nil];
  NSString *body = [params convertToURIParameterString];

  NSURL *url = nil;
  if ([body length] == 0)
  {
    url = [NSURL URLWithString:[NSString stringWithFormat:@"%@", urlString]];
  }
  else
  {
    url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", urlString, body]];
  }

  __block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
  request.delegate = self;
  request.requestMethod = kSKMethodPOST;

  [request addFile:[localPath path] forKey:@"file"];

  //
  // Dropbox uses OAuth to handle its authentication, so we need to pass along the requested
  // tokens and secrets so that we get our stuff back.
  //  
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  NSString *token = [defaults objectForKey:@"oauth_token"];
  NSString *secret = [defaults objectForKey:@"oauth_secret"];  

  [request buildPostBody]; 
  NSData *authBody = request.postBody; 

  NSString *header = OAuthorizationHeader(url, request.requestMethod, authBody, kOAuthConsumerKey, kOAuthConsumerSecret, token, secret);  
  [request addRequestHeader:@"Authorization" value:header];  

  [request setCompletionBlock:^{
    NSDictionary *result = (NSDictionary *)[[request responseString] JSONValue];    
    [self.activeUploads removeObjectForKey:remotePath];
    handler(result, nil);
  }];

  [request setFailedBlock:^{
    NSError *error = request.error;
    [self.activeUploads removeObjectForKey:remotePath];
    handler(nil, error);
  }];

  [self.activeUploads setObject:request forKey:remotePath];

  [self.queue addOperation:request];
}

我看到了one example该人使用预处理器定义并将 OCMock 注入(inject)实际代码库。这对我来说似乎是错误的。

测试这样一段代码的最佳策略是什么?

最佳答案

这个答案与 OCMock 没有具体关系,因此它可能不是您正在寻找的内容,但是......

我会做这样的事情:

__block BOOL testPassed = NO;

[engine uploadFileWithFilename:@"FileTest.png" 
                  toRemotePath:@"/" 
                 fromLocalPath:localFilePath 
         withCompletionHandler:^(id response, NSError *error) {
    if (error)
    {
      return;
    }

    testPassed = YES;
  }];

[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode 
                      beforeDate:[[NSDate date] dateByAddingTimeInterval:10]];

// make sure that testPassed is YES...

这样,您就会阻塞,直到其中一个回调进入主运行循环。

关于cocoa - OCMock 异步 block 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4866211/

相关文章:

Cocoa:NSArrayController 的自定义 Controller key

python - 使用 python/django 关闭套接字并避免 Errno 10054 的正确方法是什么

Android 单元测试包路径错误

android - 模拟 Android AssetManager

ios - Objective-C:存储在集合中的 block 的初始化

iphone - 后台任务 block 功能未完成

swift - 如何在 Swift 中将 NSImage 写入 JPEG 文件?

objective-c - NSPersistentStoreCoordinatorexecuteRequest 是否没有任何上下文,可以安全地获取 _objectIDs_

cocoa - 开始 Mac OS X 编程

objective-c - 为什么这个 block 不是全局的?