Как проверить класс, который делает HTTP-запрос и анализировать данные ответа в Obj-C? - PullRequest
4 голосов
/ 21 марта 2010

У меня есть класс, который должен сделать HTTP-запрос к серверу, чтобы получить некоторую информацию. Например:

- (NSUInteger)newsCount {
    NSHTTPURLResponse *response;
    NSError *error;
    NSURLRequest *request = ISKBuildRequestWithURL(ISKDesktopURL, ISKGet, cookie, nil, nil);
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if (!data) {
        NSLog(@"The user's(%@) news count could not be obtained:%@", username, [error description]);
        return 0;
    }
    NSString *regExp = @"Usted tiene ([0-9]*) noticias? no leídas?";
    NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
    NSArray *match = [stringData captureComponentsMatchedByRegex:regExp];
    [stringData release];
    if ([match count] < 2)
        return 0;
    return [[match objectAtIndex:1] intValue];
}

Дело в том, что я занимаюсь модульным тестированием (используя OCUnit) каркаса дырок, но проблема в том, что мне нужно смоделировать / подделать то, что отвечает NSURLConnection, чтобы протестировать различные сценарии и потому что я не могу передать сервер для проверки моей структуры.

Так что вопрос Какой лучший способ сделать это?

1 Ответ

4 голосов
/ 10 июля 2010

Всегда сложно тестировать методы, которые вызывают методы класса, такие как NSURLConnection sendSynchronousRequest

Вот несколько вариантов:

a) Используйте макрос invokeSuperfter Мэтта Галлахера для перехвата вызова. Ваш юнит-тест будет содержать такой код:

@implementation NSURLConneciton (UnitTests)

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error {
    if (someFlagYourTestUsesToInterceptTheCall) {        
        // return test NSData instance      
    }   
    return invokeSupersequent(request, &response, &error);
}

@end

Затем вы устанавливаете someFlagYourTestUsesToInterceptTheCall, чтобы заставить его перехватывать вызов и возвращать ваши тестовые данные.

b) Другая альтернатива - переместить этот вызов в собственный метод в тестируемом классе:

-(NSData *)retrieveNewsCount:(NSURLRequest *)request {
    NSHTTPURLResponse *response;
    NSError *error;
    return [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
}

Затем перехватите этот вызов в вашем тестовом примере, используя OCMock:

-(void)testNewsCount {
    // instantiate your class
    id myObject = ...;
    id mock = [OCMockObject partialMockForObject:myObject];
    [[[mock stub] andCall:@selector(mockNewsCount:) onObject:self] retrieveNewsCount:[OCMArg any]];
    NSUInteger count = [myObject newsCount];
    // validate response
    ...
}

// in the same test class:
-(NSData *)mockNewsCount:(NSURLRequest *)request {
    // return your mock data
    return mockData;
}

В этом случае OCMock stub:andCall:onObject:someMethod перехватывает только этот вызов метода вашего объекта, чтобы ввести некоторые тестовые данные во время теста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...