Question

I have a class which is a kind of wrapper for NSOperationQueue. It allows to enqueue network requests using blocks. Currently the requests are executed one after another, but this can be changed in the future.

Here is the code of MyRequestsQueue class:

@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

In general, I know how to unit test asynchronous code using XCTest. But now I want to add a unit test for MyRequestsQueue that checks if queue executes only one operation at the time. Or even better - test that number of currently executing operations is not greater than maxConcurrentOperationCount. I tried to observe operationCount property of self.queue, but the documentation says I shouldn't rely on it. How can I achieve it?

EDIT: My tests use the following pattern:

@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");
}

the WAIT_WHILE macro is from AGAsyncTestHelper.

Was it helpful?

Solution

I would recommend rethinking your testing strategy.

But now I want to add a unit test for MyRequestsQueue that checks if queue executes only one operation at the time. Or even better - test that number of currently executing operations is not greater than maxConcurrentOperationCount.

Both of these tests would be testing Apple's implementation of NSOperationQueue, which wouldn't gain you anything. You don't want to be unit testing code you don't own, and in general you should assume that Apple have correctly tested their own code. If NSOperationQueue ran more concurrent operations than it should, Apple would have a big problem!

Instead, I would simply test that after it's been initialized, your MyRequestsQueue has set the correct maxConcurrentOperationCount on its NSOperationQueue.

OTHER TIPS

Will it help? check the count property.

@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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top