单元测试一个执行选择器并等到它完成的函数

时间:2016-06-15 09:51:56

标签: ios objective-c unit-testing nsthread ocmock

我有一个MyService类继承NSThread

头:

@interface MyService : NSThread {
  -(void) startMe;
  -(void) doTask;
  ...
}

实现:

@implementation MyService
  -(void)startMe {
   [self start];
  }
  -(void) doTask {
    [self performSelector:@selector(checkData:) onThread:self withObject:nil waitUntilDone:YES];
  }

  -(void) checkData {
    ...
    // NOTE: dataChecked is an instance variable.
    dataChecked = YES;
  }
@end

我想对上面的-(void)doTask进行单元测试,并验证是否真的调用了-(void)checkData。我使用OCMock library来部分模仿MyService&尝试了以下方式:

-(void) testCheckData {
  // partial mock MyService
  id myService = [OCMockObject partialMockForObject:[MyService getInstance]];
  [myService startMe];

  // function to test
  [myService doTask];

  // I wait 2 seconds for checkData to finish its work
  dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
    dispatch_after(delayTime, dispatch_get_main_queue(), ^(void){
        // When running this test case, these code is never called & test passed successfully, WHY?
        NSLog(@"Check if checkData does its work");
        XCTAssertTrue([self isDataChecked]);
    });
}

两个问题:

Q1。如上所述,在我的测试案例中,我致电-(void)doTask& 等待2秒,期望执行-(void)checkData,然后断言结果,但在运行测试用例时,它不会在dispatch_after(...)&运行测试用例。测试成功通过,为什么它没有运行块?

Q2。-(void)doTask这样调用NSObject#performSelector:onThread:withObject:waitUntilDone:的函数进行单元测试的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

<强> Q1

如果您无法更改doTask以使其可测试,则必须使用XCTestExpectation等待测试完成。此外,您应该忙于循环,在每次迭代时检查变量,而不是等待预设的时间。您可以在预期之后设置超时,以便在一段合理的时间后触发故障。

// setup expectation    
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    while (dataChecked == NO);
    // signal expectation
});

// wait for expectation

<强> Q2

如果你必须知道成功测试它的方法的实现,它不适合单元测试。测试方法如何调用其他方法并不重要。只有当副作用同步或异步完成时才重要。