Тестирование многопоточности - PullRequest
4 голосов
/ 28 июля 2011

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

Сейчас у меня настроены модульные тесты, чтобы убедиться, что все работает правильно в однопоточной среде.

Что я могу сделать, чтобы убедиться, что это выполняется в многопоточности? Я хотел бы продолжить использовать модульное тестирование, но не уверен, как выполнить тестирование многопоточности в модульных тестах.

Уточнение: я реализую многопоточность, используя NSBlockOperation / NSOperationQueue.

Ответы [ 2 ]

3 голосов
/ 28 июля 2011

Чтобы проверить что-то подобное, вы захотите контролировать NSOperationQueue в своих тестах.

Предположим, что класс, который вы тестируете, называется MySubject. Во-первых, вам необходимо провести рефакторинг, чтобы мы могли добавить NSOperationQueue, что позволит использовать его для тестирования. Так что избавьтесь от всех вхождений [NSOperationQueue mainQueue] и замените их переменной класса. Инициализируйте эту переменную класса из параметра в конструкторе MySubject. В результате вам придется изменить все экземпляры MySubject, чтобы передать [NSOperationQueue mainQueue].

@interface MySubject: NSObject {
  NSOperationQueue* operationQueue;
}
@end

@implementation MySubject
-(MySubject*)initWithOperationQueue:(NSOperationQueue*)queue {
  if ( self = [super init] ) {
    self.operationQueue = [queue retain];
  }
  return self;
}

-(void)dealloc {
  [operationQueue release];
}

-(void)startOperations {
  [operationQueue addOperation:...];
  [operationQueue addOperation:...];
}
@end

А клиенты теперь выглядят так:

subject = [[MySubject alloc] initWithOperationQueue:[NSOperationQueue mainQueue]];
[subject startOperations];

Теперь для тестов вы можете создать простую очередь для тестирования ... для этого потребуется реализовать любые методы, используемые вашим субъектом.

@interface MyTestOperationQueue: NSMutableArray {
}
@end

@implementation MySubject

-(void)addOperation:(NSOperation*)operation {
  [self addObject:operation];
}
@end

А теперь ваш тест может выглядеть так:

testQueue = [[MyTestOperationQueue alloc] init];
subject = [[MySubject alloc] initWithOperationQueue:testQueue];
[subject startOperations];

// You may want to have other tests that execute the queue operations
// in a different order
[[testQueue objectAtIndex:0] start];
[[testQueue objectAtIndex:0] waitUntilFinished];
[[testQueue objectAtIndex:1] start];
[[testQueue objectAtIndex:1] waitUntilFinished];

// Verify results

Конечно, этот вид теста не сможет проверить, что параллельные операции безопасны для одновременного выполнения, но это может охватывать множество случаев, которые вас заинтересуют при попытке создать классы. .

2 голосов
/ 28 июля 2011

Короче, ты не можешь.По крайней мере, вы не можете получить почти 100% покрытия тестированием.С потоками все от одновременного ввода-вывода до подсчета ядер, нагрузки на память и активности в других процессах (или тех же процессах) будет влиять на планирование потоков.

Для модульных тестов обычно требуется, чтобы модульный тест блокировался домногопоточная подсистема делает все, что нужно.Часто поток модульного тестирования асинхронно порождает любую выполняемую работу, а затем блокируется до появления сигнала (вид потока, а не сигнал ()).Есть много разных способов сделать это, очевидно, и многие детали будут зависеть от вашего приложения;нужно запустить петли?используя GCD (надеюсь)?и т.д ....

...