SenTestingKit in Xcode 4: Asynchronous testing?

2020-02-07 16:55发布

问题:

I have been searching for a way to use SenTestingKit to do some integration testing between my client-side code and our server. I haven't had any luck. It seems that once the code is run in a method, the object gets destroyed. This means that any asynchronous responses never call the selectors.

Questions:

  1. Is there a way to keep the object instantiated until such time as I see fit to destroy it - ie. after the tests have completed?
  2. If not, how could I create a class that blocks (ie. acts synchronously) until the tests are completed?

FYI, I'm running a test server where I know the expected results.

I've done a fair bit of Googling but haven't seen proof one way or another about this. I'm sure others would be interested as well.

回答1:

Two options:

  • switch to GHUnit, which actually contains support for waiting for asynchronous events
  • narrow the design of your tests so that you can test things as they stand. E.g. test that your controller code causes a selector to be detached and run, and (separately) test that this selector does what it ought. If both of those things work, then you can be confident that your controller detaches the correct work.


回答2:

You can use a semaphore to wait until the asynchronous method finishes.

- (void)testBlockMethod {
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    // Your block method eg. AFNetworking
    NSURL *url = [NSURL URLWithString:@"http://httpbin.org/ip"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        NSLog(@"IP Address: %@", [JSON valueForKeyPath:@"origin"]);
        STAssertNotNil(JSON, @"JSON not loaded");
        // Signal that block has completed
        dispatch_semaphore_signal(semaphore);
    } failure:nil];
    [operation start];

    // Run loop
    while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    dispatch_release(semaphore);

}

http://samwize.com/2012/10/03/sentestingkit-does-not-support-wait-for-blocks/



回答3:

Kiwi supports asynchronous testing. Kiwi is a Behavior Driven Development (BDD) library for iOS that extends SentTestingKit (OCUnit), so it's easy to set up & use.

Also, check out:

  • iOS Tests/Specs TDD/BDD and Integration & Acceptance Testing.
  • Testing asynchronous code on iOS with OCunit


回答4:

This project https://github.com/hfossli/AGAsyncTestHelper has a very convenient macro

WAIT_WHILE(<expression_to_evaluate>, <max_duration>);

Which ables you to write the test like so

- (void)testDoSomething {

    __block BOOL somethingIsDone = NO;

    [MyObject doSomethingAsyncThenRunCompletionBlockOnMainQueue:^{
        somethingIsDone = YES;
    }];

    WAIT_WHILE(!somethingIsDone, 1.0); 
    NSLog(@"This won't be reached until async job is done");
}


回答5:

Checkout the SenTestingKitAsync project - https://github.com/nxtbgthng/SenTestingKitAsync. The related blog is here - http://www.objc.io/issue-2/async-testing.html