ドキュメントが分かりにくかったので自分で書いてみた。
■テスト対象のクラス
ASIHTTPRequestを使った普通のクラス。
MyHTTP.h
#import <Foundation/Foundation.h> #import "MyHTTPDelegate.h" @class ASIHTTPRequest; @class MyHTTPDelegate; @interface MyHTTP : NSObject { id <MyHTTPDelegate> delegate; } @property (nonatomic, retain) id delegate; - (void)loadData; - (void)requestFinished:(ASIHTTPRequest *)request; - (void)requestFailed:(ASIHTTPRequest *)request; @end
MyHTTP.m
以下のように実装する。ASIHTTPRequestを使った事があるならばお手の物だ。
#import "MyHTTP.h" #import "ASIHTTPRequest.h" #import "SBJson.h" // 今回は触れないけど通信するので圏外判定に使っている #import "UIDevice-Reachability.h" #import "Reachability.h" #define URL @"http://example.org/api/data" @implementation MyHTTP @synthesize delegate; // 通信して更新する - (void)loadData { if([[UIDevice currentDevice] networkAvailable] == YES){ ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:URL]]; [request setDelegate:self]; [request setRequestMethod:@"GET"]; [request startAsynchronous];// 非同期通信の開始 } else{ // 圏外の時 = cahceから再現させる } } #pragma mark - #pragma mark ASIHTTPRequestDelegate - (void)requestFinished:(ASIHTTPRequest *)request { SBJsonParser *parser = [[SBJsonParser alloc] init]; NSArray *json = [parser objectWithString:[request responseString] error:nil]; if(json != nil && [json count] > 0){// success [delegate reflectData:json]; } [parser release]; } - (void)requestFailed:(ASIHTTPRequest *)request { NSError *error = [request error]; } @end
■テストクラス
MyHTTPTest.h
以下のようにGHAsyncTestCaseを継承する。
#import <GHUnitIOS/GHUnit.h> @class MyHTTP; @interface MyHTTPTest : GHAsyncTestCase { MyHTTP *http; } @property (nonatomic, retain) MyHTTP *http; @end
MyHTTPTest.m
以下のように実装する。
#import "MyHTTPTest.h" #import "MyHTTP.h" @implementation MyHTTPTest @synthesize http; - (void)setUpClass { http = [[MyHTTP alloc] init]; [http setDelegate:self]; } - (void)tearDownClass { [http release]; } - (void)testLoadData { // 非同期処理が始まる前の準備 [self prepare]; // 非同期処理を実行する [self performSelector:@selector(startAsynchronous) withObject:nil afterDelay:0.1]; // どのくらい[結果]が帰ってくるのを待つか指定する(ここでは3秒待つことにした) [self waitForStatus:kGHUnitWaitStatusSuccess timeout:3.0]; } - (void)startAsynchronous { [http loadData]; } #pragma mark - #pragma mark MyHTTPDelegate - (void)reflectData:(NSArray *)json { NSLog(@"json:%d", [json count]); @try { GHAssertFalse( !!([json count] == 0), @"success to transfer for popular"); [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testLoadData)];// テストの[結果]を通知 } @catch (NSException *exception) {// アサーションに失敗した場合 [self notify:kGHUnitWaitStatusFailure forSelector:@selector(testLoadData)];// テストの[結果]を通知 } } @end
GHAssert系のメソッドはテストが失敗した場合にExceptionを発生させるので、上述のようにcatchしないとユニットテスト自体がクラッシュする。ちなみに以下のように書いても問題なくテストできた。
#import "MyHTTPTest.h" #import "MyHTTP.h" @implementation MyHTTPTest @synthesize http; - (void)setUpClass { http = [[MyHTTP alloc] init]; [http setDelegate:self]; } - (void)tearDownClass { [http release]; } - (void)testLoadData { // 非同期処理が始まる前の準備 [self prepare]; // 非同期処理を実行する [http loadData]; // どのくらい[結果]が帰ってくるのを待つか指定する(ここでは3秒待つことにした) [self waitForStatus:kGHUnitWaitStatusSuccess timeout:3.0]; } #pragma mark - #pragma mark MyHTTPDelegate - (void)reflectData:(NSArray *)json { NSLog(@"json:%d", [json count]); @try { GHAssertFalse( !!([json count] == 0), @"success to transfer for popular"); [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testLoadData)];// テストの[結果]を通知 } @catch (NSException *exception) {// アサーションに失敗した場合 [self notify:kGHUnitWaitStatusFailure forSelector:@selector(testLoadData)];// テストの[結果]を通知 } } @end
performSelectorメソッドの有用性が分からない。
■おまけ
実はMyHTTPクラスには通信ができなかった時の事を考慮して、キャッシュから呼び出す機能がある。以下のようにSELをプロパティに持たせる事で通知先を分岐するようにした。
#import "MyHTTPProxyTest.h" #import "MyHTTPProxy.h" @implementation MyHTTPProxyTest @synthesize http; @synthesize selector; - (void)setUpClass { http = [[MyHTTPProxy alloc] init]; [http setDelegate:self]; } - (void)tearDownClass { [http release]; } - (void)testLoadCache { [self setSelector:@selector(testLoadCache)]; [self prepare]; [self performSelector:@selector(startLoadCache) withObject:nil afterDelay:0.01]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:3.0]; } - (void)testLoadData { [self setSelector:@selector(testLoadData)]; [self prepare]; // Do asynchronous task here [self performSelector:@selector(startAsynchronous) withObject:nil afterDelay:0.01]; // Wait for notify [self waitForStatus:kGHUnitWaitStatusSuccess timeout:3.0]; } - (void)startLoadCache { [http loadCache]; } - (void)startAsynchronous { [http loadData]; } #pragma mark - #pragma mark MyHTTPDelegate - (void)reflectData:(NSArray *)json { NSLog(@"json:%d", [json count]); @try { GHAssertFalse( !!([json count] == 0), @"success to transfer"); [self notify:kGHUnitWaitStatusSuccess forSelector:[self selector]]; } @catch (NSException *exception) { [self notify:kGHUnitWaitStatusFailure forSelector:[self selector]]; } } @end