4

当我将应用程序从单线程转移到多线程时,我试图确保我的 ObjC 多线程实现是正确的。

现在我已经设置了单元测试,以确保在单线程环境中一切正常。

我能做些什么来确保这在多线程中成立?我想继续使用单元测试,但不确定如何在单元测试中测试多线程。

澄清:我正在使用 NSBlockOperation / NSOperationQueue 实现多线程。

4

2 回答 2

3

要测试这样的东西,您需要NSOperationQueue在测试中进行控制。

假设您正在测试的类被称为MySubject. 首先,您需要对其进行重构,以便我们可以注入一个NSOperationQueue--that 将允许 use 替换它以进行测试。所以摆脱所有出现的[NSOperationQueue mainQueue]并用类变量替换它们。MySubject从的构造函数中的参数初始化该类变量。因此,您必须将所有实例更改MySubject为 pass [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

当然,这种测试无法验证并发操作是否可以安全地同时执行,但这可以涵盖很多您在尝试设计类时会感兴趣的情况。

于 2011-07-28T00:26:29.887 回答
2

简而言之,你不能。至少,您无法获得接近 100% 的测试覆盖率。对于线程,从同时 I/O 到核心计数到内存压力再到其他进程(或同一进程)中的活动,一切都会影响线程调度。

对于单元测试,您通常希望单元测试阻塞,直到线程子系统完成它需要做的任何事情。通常,单元测试线程会异步生成任何需要完成的工作,然后阻塞直到出现信号(线程类型的信号,而不是 signal())。很明显,有很多不同的方法可以做到这一点,而且很多细节都是针对你的应用程序的;需要运行循环?使用 GCD(希望如此)?ETC....

于 2011-07-27T22:55:44.800 回答