我該如何測試我的NSURLConnection委託? 我做了一個ConnectionDelegate類,它符合不同的協議,以將數據從Web提供給不同的ViewController。在我變得太遠之前,我想開始編寫我的單元測試。 但我不知道如何測試他們作爲一個單位沒有互聯網連接。我也想我應該做什麼來處理異步回調。如何單元測試一個NSURLConnection委託?
回答
雖然這與Jon的迴應類似,但無法將其納入評論。第一步是確保你沒有創建一個真正的連接。實現此目的的最簡單方法是將連接的創建拉入工廠方法,然後在測試中替換工廠方法。有了OCMock的部分模擬支持,這可能看起來像這樣。
在你真正的類:
- (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]];
現在,當被測你的對象嘗試創建它實際上得到測試所創建的虛擬連接的URL連接。虛擬連接不必是有效的,因爲我們沒有啓動它,它永遠不會被使用。如果你的代碼使用連接,你可以返回另一個模擬,一個嘲笑NSURLConnection。
第二步是調用觸發NSURLConnection的創建你的對象上的方法:由於被測對象沒有使用真正的方面,我們現在可以調用從委託方法
[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];
就是這樣:對於我們使用另一種模擬的NSURLResponse,響應數據是從已定義的其他地方測試中的字符串創建。您已經有效地僞造了測試對象與連接之間的所有交互,現在您可以檢查它是否處於應該處於的狀態。
如果您想查看一些「真實」代碼,查看使用NSURLConnections的CCMenu項目中的類的測試。這有點令人困惑,因爲被測試的類也被命名爲連接。
這是我做的:
- 獲取XAMPP控制面板 http://www.apachefriends.org/en/xampp.html
- 啓動Apache服務器
- 在你
~/Sites
文件夾,把一個測試文件(任何你想要的數據,我們會打電話給它my file.test
)。 - 使用URL啓動您的代理http://localhost/~username/myfile.test
- 停止Apache服務器時,不使用它。
我在單元測試中避免了聯網。相反:
- 我在方法中分離NSURLConnection。
- 我創建了一個測試子類,覆蓋該方法以刪除NSURLConnection的所有痕跡。
- 我寫了一個測試,以確保所需的方法在需要時被調用。然後我知道它會在現實生活中引發NSURLConnection。
然後我專注於更有趣的部分:合成具有各種特徵的模擬NSURLResponses,並將它們傳遞給NSURLConnectionDelegate方法。
在我的委託方法中嘲笑或存根NSURLConnection怎麼樣?我將NSURLConnection分類爲包含接收到的NSData,接收者(我將寫入的JSON獲取者)以及用於調用它的請求。 – Moxy 2012-03-29 06:36:49
看完我的代碼並再次閱讀您的答案後,我發現我正處在正確的軌道上! – Moxy 2012-03-29 07:35:28
我的NSURLConnection已經被隔離在一個方法 - (void)sendRequest:(NSURLRequest *)請求forReceiver:(id
我最喜歡的做法是將NSURLProtocol子類化,然後讓它響應所有http請求 - 或者其他協議。然後,您在-setup
方法中註冊測試協議,並將其註銷到-tearDown
方法中。 然後,您可以使用此測試協議將一些衆所周知的數據提供回您的代碼,以便您可以在單元測試中驗證它。
我寫了一些關於這個問題的博客文章。與您的問題最相關的可能是Using NSURLProtocol for Injecting Test Data和Unit Testing Asynchronous Network Access。
您可能還想看看我的以前的文章中描述的ILCannedURLProtocol。來源可在Github。
我讀了兩篇文章,他們非常有趣。我實際上開始就如何解決這個問題感謝他們。我不認爲我需要子類化NSURLProtocol(並且我更喜歡在未來會更改它的情況下不這樣做),因爲我的連接委託不處理數據。我正在使用我的接收器作爲觀察者。所以通過重寫開始連接的方法,我可以提供我想要的數據。 PS:偉大的博客!我已加入IL;) – Moxy 2012-03-29 11:52:58
感謝您的意見。只是爲了澄清,ILCannedURLProtocol並不打算找到生產代碼的方式,所以我不會太擔心底層NSURLProtocol的變化。如果發生這種情況,那只是對您的測試設置的改變。 – 2012-03-29 11:58:38
[MockNSURLConnection](https://github.com/wfleming/MockNSURLConnection)與您的方法非常吻合。 – snez 2012-12-20 14:22:21
EDIT(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循環並執行測試。完成。
太棒了。給我足夠的東西,使東西工作:)謝謝。 – Johan 2013-12-24 13:36:53
你可能想這給一個機會:
https://github.com/marianoabdala/ZRYAsyncTestCase
下面是測試一個NSURLConnection的是單位的一些示例代碼: https://github.com/marianoabdala/ZRYAsyncTestCase/blob/12a84c7f1af1a861f76c7825aef6d9d6c53fd1ca/SampleProject/SampleProjectTests/SampleProjectTests.m#L33-L56
嘗試描述您的文章中鏈接包含的內容。 – 2013-06-27 01:49:45
- 1. 「委託」類的單元測試
- 2. 單元測試的委託方法
- 3. 單元測試一個類與事件和委託
- 4. NSURLConnection委託方法
- 5. NSURLConnection委託方法
- 6. UITableView委託觸發NSURLConnection委託
- 7. NSURLConnection委託和線程 - iPhone
- 8. NSURLConnection和對象委託
- 9. NSURLConnection的委託方法
- 10. NSURLConnection的委託方法
- 11. iOS NSURLConnection委託問題
- 12. Rails:如何測試委託方法?
- 13. 測試委託回調
- 14. 單元測試NSURLConnection的sendAsynchronousRequest與OCMockito
- 15. 使用NSURLConnection進行單元測試
- 16. 委託方法不適用於Jmockit單元測試
- 17. 單元測試委託操作被稱爲
- 18. 單元測試應用程序委託applicationWillResignActive
- 19. C#Moq單元測試與Lambda表達式或Func委託
- 20. 爲NSURLSession設置委託並對其進行單元測試
- 21. 在C#中的異步委託調用單元測試
- 22. c#單元測試委託事件處理程序
- 23. 在單元測試的所有方法是否委託檢查
- 24. 如何在uicollectionview中檢測單元格didselect委託方法
- 25. 如何從NSURLConnection委託發送多個url請求?
- 26. 如何單元測試一個PHP method_exists()
- 27. 如何在調用UITableview委託在uiviewcontroller中委託方法之前調用NSURLConnection委託方法
- 28. 如何正確設置RunLoop以便單元測試NSURLConnection?
- 29. Parallel.Foreach委託調用另一個委託
- 30. 單元測試委派方法
這非常有用。我試圖擴展它來覆蓋來回的對話,而不是一次性的請求/響應場景,但我沒有太多的運氣。我發佈了一個單獨的問題:http://stackoverflow.com/questions/16472878/how-can-you-use-ocmock-with-nsurlconnection-delegate-for-a-series-of-mock-networ – Gruntcakes 2013-05-09 23:34:19