0

ボタンのクリックが発生したときに位置情報サービスが開始されることを確認するためのテストを作成しています。これには、電話に位置情報サービスが利用可能であることを確認するための非常に単純なifステートメントが必要です。

現在の作業テストは次のようになります

- (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];
    }
}

このメソッドがiOS4.0で非推奨になったことを除いて、すべて問題ありません。そのため、代わりにクラスメソッド[CLLocationManagerlocationServicesEnabled]を使用する必要があります。

問題は、ocmockがこの機能をサポートしているかどうかがわからないようで、サポートしていない場合は、今のところこの問題をどのように回避する必要があるかです。

4

4 に答える 4

3

うーん、methodExchangeを使用できます。メソッドを使い終わったら、必ず元のメソッドに戻すようにしてください。それはハッキーのようですが、私はより良い解決策を見つけていません。スタブについても同様のことをしました[NSDatedate]

@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

編集:私はあなたが検証していると思ったが、あなたはスタブしているようだ。更新されたコード

于 2012-03-26T01:13:27.523 に答える
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 ...
}
于 2012-03-26T19:26:31.993 に答える
1

そうは思わない。私が考えることができる唯一のアプローチは、部分的なモックを使用してから、ランタイム呼び出しを使用して、必要な実装でスウィズルすることです。

実行可能ですが、複雑です。

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

于 2012-03-26T01:13:14.783 に答える
0

これはOCMockでサポートされています。

[[[[mockLocationManagerClass stub] classMethod] andReturnValue:OCMOCK_VALUE(YES)] locationServicesEnabled];
于 2015-01-21T22:16:18.370 に答える