1

私は、基本クラスを使用して一般的に使用される機能を再利用する非常に単純なWebサービスを使用しています。テスト対象のメインメソッドは、URLを作成するだけで、この引数を使用してスーパー/ベースメソッドを使用します。

- (void)getPlacesForLocation:(Location *)location WithKeyword:(NSString *)keyword
{
    NSString *gps = [NSString stringWithFormat:@"?location=%@,%@", location.lat, location.lng];
    NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@%@", self.baseurl, gps]];
    [super makeGetRequestWithURL:url];
}

これが基本メソッドの定義です

@implementation WebService
@synthesize responseData = _responseData;

- (id)init
{
    if (self == [super init])
    {
        self.responseData = [NSMutableData new];        
    }

    return self;
}

- (void)makeGetRequestWithURL:(NSURL *)url
{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
    request.HTTPMethod = @"GET";

    [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

私のテストでは、テスト対象のオブジェクトを呼び出したいので、部分的なモックを作成しましたが、スーパーメソッドが特定の方法で呼び出されていることを確認する機能が必要です。

- (void)testGetRequestMadeWithUrl
{
    self.sut = [[SomeWebService alloc] init];
    Location *location = [[Location alloc] initWithLatitude:@"-33.8670522" AndLongitude:@"151.1957362"];
    NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@%@", self.sut.baseurl, @"?location=-33.8670522,151.1957362"]];
    id mockWebService = [OCMockObject partialMockForObject: self.sut];
    [[mockWebService expect] makeGetRequestWithURL:url];
    [self.sut getPlacesForLocation:location WithKeyword:@"foo"];
    [mockWebService verify];
}

しかし、このテストを実行すると、次のエラーで失敗します。

予期されたメソッドが呼び出されませんでした:makeGetRequestWithURL:https:// ...

NSLogをbaseメソッドに入れると、ocunitテストを実行したときに表示されるため、このメソッドはモックではないことがわかります(明らかに実行されており、必要に応じてモックではありません)。

テストを変更/実装コードをリファクタリングして、探しているアサーションを取得するにはどうすればよいですか?

4

1 に答える 1

3

これは興味深いケースです。私の仮定では、「super」を「self」に置き換えると、すべてが期待どおりに機能します。

- (void)getPlacesForLocation:(Location *)location WithKeyword:(NSString *)keyword
{
    NSString *gps = [NSString stringWithFormat:@"?location=%@,%@", location.lat, location.lng];
    NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@%@", self.baseurl, gps]];
    [self makeGetRequestWithURL:url];
}

問題は、部分的なモックがその場でサブクラスを作成することによって実装されることです。「スーパー」を使用する場合、メソッドのルックアップは親クラス、この場合は基本クラスで開始されます。つまり、ランタイムは、部分モックによって作成されたサブクラスに実装されたメソッドを認識しません。

あなたの質問に対する別の答えは、デザインを変更することです。クラス階層を使用するのではなく、2つのクラスを使用します。1つのクラスがURLの作成を担当し、もう1つのクラスがリクエストの作成を担当します。そうすれば、リクエストメーカーを単純に置き換えることができるため、部分的なモックは必要ありません。単一責任の原則[1]および継承に対する構成[2]を参照してください。

[1] http://en.wikipedia.org/wiki/Single_responsibility_principle

[2] http://en.wikipedia.org/wiki/Composition_over_inheritance

于 2012-03-20T12:06:25.743 に答える