【问题标题】:Testing multi-threading测试多线程
【发布时间】:2011-07-27 21:45:48
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: objective-c unit-testing xcode4 osx-lion


    【解决方案1】:

    要测试这样的东西,您需要在测试中控制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
    

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

    【讨论】:

    • 啊。我更感兴趣的是测试操作是否可以安全地并发。没有内存错误等。不过,这是个好主意。但是直接调用 MySubject 的操作似乎更简单。可能通过将它们分配给init 的块变量。这似乎是一种不便。但无论如何都是很好的信息。
    【解决方案2】:

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

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

    【讨论】:

    • 我正在使用 NSBlockOperation / NSOperationQueue 实现多线程。
    • 好;如今,手动生成线程不是最佳选择。尽管如此,评论仍然有效,但是——虽然不可能完全覆盖并发系统——但进行一些测试肯定比没有测试好!
    猜你喜欢
    • 2011-07-29
    • 2017-05-14
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-19
    相关资源
    最近更新 更多