Модульные тесты для NSOperationQueue с maxConcurrentOperationCount

У меня есть класс, который является своего рода оболочкой для NSOperationQueue. Это позволяет ставить в очередь сетевые запросы с помощью блоков. В настоящее время запросы выполняются один за другим, но это может быть изменено в будущем.

Вот код класса MyRequestsQueue:

@interface MyRequestsQueue ()

@property(nonatomic, strong) NSOperationQueue* queue;

@end

@implementation MyRequestsQueue

-(instancetype)init
{
    self = [super init];
    if(!self) {
        return nil;
    }

    self.queue = [[NSOperationQueue new] autorelease];
    self.queue.maxConcurrentOperationCount = 1;

    return self;
}

-(void)addRequestBlock:(void (^)())request
{
    NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:request];
    [self.queue addOperation:operation];
}

@end

В общем, я умею тестировать асинхронный код с помощью XCTest. Но теперь я хочу добавить модульный тест для MyRequestsQueue, который проверяет, выполняет ли очередь только одну операцию за раз. Или еще лучше - проверить, что количество выполняемых в данный момент операций не превышает maxConcurrentOperationCount. Я пытался наблюдать свойство operationCount self.queue, но документация говорит, что я не должен на это полагаться. Как я могу достичь этого?

РЕДАКТИРОВАТЬ: Мои тесты используют следующий шаблон:

@interface MessageRequestQueueTest : XCTestCase

@property(nonatomic, strong) MessageRequestsQueue* reuqestQueue;
@property(nonatomic, assign) NSInteger finishedRequestsCounter;

@end
// setUp method ommited - simply initializes self.requestQueue


-(void)testAddedRequestIsExecuted
{
    [self.reuqestQueue.queue setSuspended:YES];

    __weak __typeof(self) weakSelf = self;
    [self.reuqestQueue addRequestBlock:^{
        ++weakSelf.finishedRequestsCounter;
    } withName:kDummyRequestName];

    [self.reuqestQueue.queue setSuspended:NO];

    WAIT_WHILE(0 == self.finishedRequestsCounter, 0.1);
    XCTAssertEqual(self.finishedRequestsCounter, 1, @"request should be executed");
}

макрос WAIT_WHILE взят из AGAsyncTestHelper.


person Michał Ciuba    schedule 20.01.2014    source источник
comment
Можете ли вы опубликовать свой метод модульного тестирования?   -  person Greg    schedule 20.01.2014
comment
Я добавил один из моих методов модульного тестирования.   -  person Michał Ciuba    schedule 20.01.2014


Ответы (2)


Я бы порекомендовал пересмотреть вашу стратегию тестирования.

Но теперь я хочу добавить модульный тест для MyRequestsQueue, который проверяет, выполняет ли очередь только одну операцию за раз. Или еще лучше — проверить, что количество выполняемых в данный момент операций не превышает maxConcurrentOperationCount.

Оба этих теста будут тестировать реализацию Apple NSOperationQueue, что ничего вам не даст. Вы не хотите проводить модульное тестирование кода, которым не владеете, и в целом вы должны исходить из того, что Apple правильно протестировала свой собственный код. Если бы NSOperationQueue выполнял больше параллельных операций, чем следовало бы, у Apple были бы большие проблемы!

Вместо этого я бы просто проверил, что после инициализации ваш MyRequestsQueue установил правильный maxConcurrentOperationCount на свой NSOperationQueue.

person James Frost    schedule 20.01.2014
comment
тестирование maxConcurrentOperationCount кажется самым простым решением, которое работает :) Возможно, я слишком много думал об этом. - person Michał Ciuba; 20.01.2014
comment
Я думаю, что важно попытаться сопоставить усилия по тестированию конкретной функциональности с вероятностью возникновения проблемы и с тем, какую пользу вы получите от ее тестирования. Вы должны быть в состоянии с уверенностью предположить, что NSOperationQueue будет уважать maxConcurrentOperationCount, который вы установили, поэтому вам не будет полезно попробовать и проверить это - просто убедитесь, что вы правильно установили значение в первую очередь :) - person James Frost; 20.01.2014

Поможет ли это? проверьте свойство count.

@interface MyRequestsQueue ()

@property(nonatomic, strong) NSOperationQueue* queue;
@property(assign) NSUInteger count ;

@end

@implementation MyRequestsQueue

-(instancetype)init
{
    self = [super init];
    if(!self) {
        return nil;
    }

    self.queue = [[NSOperationQueue new] autorelease];
    self.queue.maxConcurrentOperationCount = 1;

    return self;
}

-(void)addRequestBlock:(void (^)())request
{
    NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{
        ++self.count ;
        request() ;
        --self.count ;
    }] ;
    [self.queue addOperation:operation];
}

@end
person KudoCC    schedule 20.01.2014
comment
Хорошая идея. Однако я не знаю, как проверить, что значение self.count никогда не превышает 1. - person Michał Ciuba; 20.01.2014