ドキュメントが分かりにくかったので自分で書いてみた。
■テスト対象のクラス
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