2014-04-29 87 views
5

我想單元測試使用XCTest在XCode 5中使用AFNEtworking的類。我遇到的問題是我的AFHTTPRequestOperation的完成塊永遠不會被執行。我認爲這是運行單元測試的XCode和AFNetworking的調度隊列之間的一些斷開。以下測試用例通過,但完成塊中的NSLog語句永遠不會到達(沒有記錄輸出,也沒有捕獲這些語句上設置的斷點)。相同的代碼在單元測試之外工作。有誰知道如何解決這個問題?我使用Nocilla來嘲笑實際的請求,結果是一樣的使用真正的服務器重新調整有效的響應?AFNetworking 2.0和單元測試

編輯,以使測試失敗,並且登錄乏塊設置

- (void)setUp 
{ 
    [super setUp]; 
    // Put setup code here. This method is called before the invocation of each test method in the class. 



    [[LSNocilla sharedInstance] start]; 

    stubRequest(@"POST", @"http://www.example.com/module/api/ping"). 
    andReturn(200). 
    withHeaders(@{@"Content-Type": @"application/json"}). 
    withBody(@"{\"success\":true}"); 

    stubRequest(@"GET", @"http://www.example.com/module/api/ping?testkey=testval"). 
    andReturn(200). 
    withHeaders(@{@"Content-Type": @"application/json"}). 
    withBody(@"{\"success\":true}"); 
} 

- (void)tearDown 
{ 
    // Put teardown code here. This method is called after the invocation of each test method in the class. 
    [super tearDown]; 

    [[LSNocilla sharedInstance] stop]; 
    [[LSNocilla sharedInstance] clearStubs]; 
} 

- (void)testSanity 
{ 
    AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init]; 
    //[policy setAllowInvalidCertificates:YES]; 

    AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.example.com/module/api/ping"]]; 
    //manager.operationQueue = [NSOperationQueue mainQueue]; 
    [manager setSecurityPolicy:policy]; 


    manager.requestSerializer = [AFJSONRequestSerializer serializer]; 
    manager.responseSerializer = [AFJSONResponseSerializer serializer]; 


    __block id resObj = nil; 
    __block id resError = nil; 

    AFHTTPRequestOperation *req = [manager POST:@"http://www.example.com/module/api/ping" 
            parameters:[NSDictionary dictionaryWithObject:@"testval" forKey:@"testkey"] 
             success:^(AFHTTPRequestOperation *operation, id responseObject) { 

              NSLog(@"Response: %@", responseObject); 
              resObj = responseObject; 
              return; 

             } 
             failure:^(AFHTTPRequestOperation *operation, NSError *error) { 

              NSLog(@"Error: %@", error); 
              resError = error; 
              return; 
             }]; 
    [req waitUntilFinished]; 

    NSLog(@"req.status: %d", req.response.statusCode); 
    NSLog(@"req.responseObj: %@", req.responseObject); 
    XCTAssertTrue(req.isFinished); 
    NSLog(@"resObj: %@", resObj); 
    NSLog(@"resError: %@", resError); 
    XCTAssertEqual([[req.responseObject objectForKey:@"success"] boolValue], YES); 

    XCTAssertEqual([[resObj objectForKey:@"success"] boolValue], YES); 
} 

控制檯輸出

 
Test Case '-[AppSupportTests testSanity]' started. 
2014-04-29 16:45:07.424 xctest[72183:303] req.status: 200 
2014-04-29 16:45:07.424 xctest[72183:303] req.responseObj: { 
    success = 1; 
} 
2014-04-29 16:45:07.424 xctest[72183:303] resObj: (null) 
2014-04-29 16:45:07.425 xctest[72183:303] resError: (null) 
/Users/jlujan/Code/AppSupport/AppSupportTests/AppSupportTests.m:114: error: -[AppSupportTests testSanity] : (([[resObj objectForKey:@"success"] boolValue]) equal to (__objc_yes)) failed: ("NO") is not equal to ("YES") 
Test Case '-[AppSupportTests testSanity]' failed (0.003 seconds). 
+0

一旦後臺操作完成,它可能調用'waitUntilFinished',但這會在調用回調之前。你可以嘗試使用['semaphore's](https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008079-CH2 -SW38)改爲[wait](http://goo.gl/lepGmc),直到[有信號](https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference .html#// apple_ref/doc/uid/TP40008079-CH2-SW39) – Rich

+1

對於異步測試,我推薦[Expecta](https://github.com/specta/expecta/)。然後你可以做一些類似'expect([[req.responseObject objectForKey:@「success」] boolValue])。will.beTruthy();'(儘管我不喜歡'beTruthy'語法!你只需要確保你設置了一個合適的超時時間[[Expecta setAsynchronousTestTimeout:15]; // seconds' – Rich

+0

這只是一個理智的檢查,以確保我的實際代碼不會導致它。使用這裏的信號量示例http://stackoverflow.com/questions/20476957/afnetworking-2-waituntilfinished-not-working,它永遠掛起。無論哪種方式,我不能在我的實際代碼中使用信號量方法。 – jlujan

回答

2

按照討論中的意見,我們發現waitUntilFinished is once the background operation is complete,它不等到完成塊被調用後。

有一個更好的異步測試框架 - Expecta
然後,而不是調用:

XCTAssertTrue(req.isFinished); 
XCTAssertEqual([[resObj objectForKey:@"success"] boolValue], YES); 

你可以這樣做:

expect(req.isFinished).will.beTruthy(); 
expect([[resObj objectForKey:@"success"] boolValue]).will.beTruthy(); 

lots of other matchers,只要確保你的設置與timeout+[Expecta setAsynchronousTestTimeout:]+setUp方法。