2012-03-25 15 views
0

ボタンクリックが発生したときに位置サービスが開始されることを確認するテストを作成しています。これには、携帯電話がロケーションサービスを利用できることを確認するための非常に簡単なifステートメントが必要です。ocmockを使用してクラスベースのメソッドで戻り値をスタブする方法

作業テストは、今この

- (void)testStartUpdatingLocationInvokedWhenLocationServicesAreEnabled 
{ 
    [[[self.locationManager stub] andReturnValue:[NSNumber numberWithBool:true]] locationServicesEnabled]; 
    [[self.locationManager expect] startUpdatingLocation]; 
    [self.sut buttonClickToFindLocation:nil]; 
    [self.locationManager verify]; 
} 

のように見える今、テスト実装では、すべての良い方法を除いて、この

- (IBAction)buttonClickToFindLocation:(id)sender 
{ 
    if ([self.locationManager locationServicesEnabled]) 
    { 
     [self.locationManager startUpdatingLocation]; 
    } 
} 

のように見えますdeprecated in iOS 4.0ました。だから、代わりにクラスメソッド[CLLocationManager locationServicesEnabled]を使う必要があります。

問題は、ocmockがこの機能をサポートしているかどうかを確認できない場合や、この問題を回避する方法が見つからない場合です。

答えて

3

hmmm、メソッドエクスチェンジを使用できます。あなたがそれを済ませた後、方法をオリジナルに戻してください。それはハッキーなようですが、私はより良い解決策を見いだせませんでした。私はあなたが検証されたと思っていますが、スタブされているようにそれはそう:私は、スタブのために何か似[NSDate日付]

@implementation 

static BOOL locationManagerExpectedResult; 

- (void)testStartUpdatingLocationInvokedWhenLocationServicesAreEnabled 
{ 
    locationManagerExpectedResult = YES; 

    method_exchangeImplementations(
     class_getClassMethod([CLLocationManager class], @selector(locationServicesEnabled)) , 
     class_getClassMethod([self class], @selector(locationServicesEnabledMock)) 
    ); 

    [self.sut buttonClickToFindLocation:nil]; 
} 

+ (BOOL)locationServicesEnabledMock 
{ 
    return locationManagerExpectedResult; 
} 

@end 

EDITを行っています。更新されたコード

+1

このimport #import を追加する必要があります。 –

1

私はそう思わない。私が考えることができる唯一のアプローチは、部分的なモックを使用し、ランタイムコールを使用して、必要な実装にうっとりすることです。

Doable but complexです。

より多くのパターン指向のソリューションは、プロトコルの背後に位置するようにロケーションサービスのチェックを抽出することがあります。次に、テスト中にプロトコルの実装にモックを使用して、必要に応じてYESまたはNOを返すことができます。実際の実装では何もしませんが、[CLLocationManager locationServicesEnabled]を返すと、テストしないで逃げることができます。

2

最も簡単な方法は、あなたのユニットテストクラスのカテゴリにlocationServicesEnabledを上書きすることです:

static BOOL locationServicesEnabled = NO; 

@implementation CLLocationManager (UnitTests) 

+(BOOL)locationServicesEnabled { 
    return locationServicesEnabled; 
} 

@end 

... 

-(void)tearDown { 
    // reset to default after each test 
    locationServicesEnabled = NO; 
    [super tearDown]; 
} 

それが唯一のテスト時に、スーパークラスのメソッドをオーバーライドし、あなたが適切に静的なグローバルを設定することができます各試験での値。

また、独自のインスタンスメソッドで小切手を折り返し、部分模擬を使用することもできます。あなたのテストで

-(BOOL)locationServicesEnabled { 
    return [CLLocationManager locationServicesEnabled]; 
} 

:テスト対象のクラスで

-(void)testSomeLocationThing { 
    MyController *controller = [[MyController alloc] init]; 
    id mockController = [OCMockObject partialMockForObject:controller]; 
    BOOL trackingLocation = YES; 
    [[[mockController stub] andReturnValue:OCMOCK_VALUE(trackingLocation)] locationServicesEnabled]; 

    // test your controller ... 
} 
0

これはOCMockによってサポートされています。これを行うには-note-に従って他人のために

[[[[mockLocationManagerClass stub] classMethod] andReturnValue:OCMOCK_VALUE(YES)] locationServicesEnabled]; 
関連する問題