unit test async function by using XCTestExpectation but it doesn't wait for the seconds I set

梦想与她 提交于 2019-12-22 17:41:38

问题


I have a MyService class which inherits NSThread:

header:

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

implementation:

@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

I want to unit test the above -(void)doTask and verify that -(void)checkData is really called. I use OCMock library to partially mock MyService.

Inspired by this tutorial (use XCTestExpectation), I tried the following way:

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

          // function to test
          [myService doTask];

          // I setup expectation
          XCTestExpectation *expectation = [self expectationWithDescription:@"data checked"];

         // run assertion asynchronisely
         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            XCTAssertTrue([self isDataChecked]);
            // expectation fulfill
            [expectation fulfill];
        });

        // wait for 5 seconds
        [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
            if (error) {
                NSLog(@"Timeout Error: %@", error);
            }
        }];
       }

However, when I run my test, the waitForExpectationsWithTimeout:handler: doesn't work, I mean it doesn't wait for 5 seconds, the assertion part run immediately after function under test get called. Why it doesn't wait 5 seconds?

====== UPDATE ======

I also tried not using async block :

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

        // function to test
        [myService doTask];

        // I setup expectation
        XCTestExpectation *expectation = [self expectationWithDescription:@"data checked"];

       // run assertion
       XCTAssertTrue([self isDataChecked]);
       // expectation fulfill
       [expectation fulfill];

       // wait for 5 seconds
       [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
          if (error) {
              NSLog(@"Timeout Error: %@", error);
          }
      }];
    }

But I still get the same problem, there is no waiting 5 seconds, the test return immediately, why?

===== AND =====

I might be wroing, if we ignore my update above & back to see my original code using async block.I think waitForExpectations:5 should do the waiting that I don't need to use while loop, why I think this way is because of that tutorial.

If we check that tutorial, it firstly show the old stye of using while loop to wait, then, it changed to expectation style which doesn't use any while loop, what it does is set expectation->start work ( assert in the completion block of its work), it also has the waitForExpectations: code, which looks exactly the same as my code with the async block. I want to understand why my original code looks the same as the tutorial but doesn't work. Do I miss something?


回答1:


As soon as you begin to waitForExpectations, your dispatch_async will get a chance to run. It will assert that your data have been checked, and then -- regardless of whether your data has been checked or not -- it marks the expectation as fulfilled. Once fulfilled, we no longer need to wait and we can finish.

That's probably not what you want to do, but it's what the code says.




回答2:


OK, solved.

I should use dispatch_after insteand of dispatch_async, because I don't have a completion block in my function under test while the example in that tutorial has one. So, I need to change to this:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        XCTAssert(...);
        [expectation fulfill];
});

If you want to use dispatch_async please check @Avi's comment, use a while loop in the async block to wait.



来源:https://stackoverflow.com/questions/37845892/unit-test-async-function-by-using-xctestexpectation-but-it-doesnt-wait-for-the

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!