AGAsyncTestHelper

by hfossli

C Macro for writing unit tests with asynchronous operations on iOS. Supports both SenTestingKit and ...

129 Stars 8 Forks Last release: Not found Other 71 Commits 5 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

AGAsyncTestHelper

C Macro for writing unit tests with asynchronous operations on iOS. Supports both SenTestingKit and XCTest.

No further support

This repo will not be developed or supported any further. You may continue to use it, but we recommend switching to expecta instead.

Install

pod 'AGAsyncTestHelper'
or
pod 'AGAsyncTestHelper/Shorthand'
with cocoapods. The latter one lets you write
WAIT_WHILE()
instead of
AGWW_WAIT_WHILE()
.

Manual installation

Copy the files found in

Source
over to your project.

If you want to have shorthand enabled (

WAIT_WHILE()
instead of
AGWW_WAIT_WHILE()
) you can either create a User Defined Build Setting within Xcode named
AGWW_SHORTHAND
OR write
#define AGWW_SHORTHAND
some clever place in your testsuite.

Overview

The macro will evaluate the expression (the first parameter) until expression is not longer true or the time limit is reached.

These macros will generate

XCTFail()
or
STFail()
if time limit is reached.
WAIT_WHILE(, limit_in_seconds, ...)
WAIT_WHILE_EQUALS(, , limit_in_seconds, ...)
WAIT_WHILE_EQUALS_WITH_ACCURACY(, , accuracy, limit_in_seconds, ...)
WAIT_WHILE_NOT_EQUALS(, , limit_in_seconds, ...)
STALL_RUNLOPP_WHILE(, limit_in_seconds)

Example: Wait for block callback

- (void)testAsyncBlockCallback
{
    __block BOOL jobDone = NO;

[Manager doSomeOperationOnDone:^(id data) {
    jobDone = YES; 
}];

WAIT_WHILE(!jobDone, 2.0);

}

WAIT_WHILE()
will stall current runloop while
!jobDone
is
TRUE
and throw an
XCTFail()
if exceeding time limit (2.0 seconds)

Example: Wait for delegate callback

- (void)testAsyncDelegateCallback
{
    Manager *manager = [Manager new];
    manager.delegate = self;
    [manager doSomeOperation];

WAIT_WHILE(!self.jobDone, 2.0);

}

  • (void)someOperationIsDoneInManager:(Manager *)manager { self.jobDone = YES; }

WAIT_WHILE()
will stall current runloop while
!self.jobDone
is
TRUE
and throw an
XCTFail()
or
STFail()
if exceeding time limit (2.0 seconds)

Example: Wait for @selector callback

- (void)testAsyncSelectorCallback
{
    [Manager doSomeOperationOnDoneTellTarget:self selector:@selector(someOperationIsDone)];

WAIT_WHILE(!self.jobDone, 2.0);

}

  • (void)someOperationIsDone { self.jobDone = YES; }

WAIT_WHILE()
will stall current runloop while
!self.jobDone
is
TRUE
and throw an
XCTFail()
or
STFail()
if exceeding time limit (2.0 seconds)

Example: Multiple values will eventually be right

- (void)testMultipleWillEventuallyBeRight
{
    UIImage *image = ...;
    [[ImageManager shared] saveImage:image];

BOOL (^cacheIsPurged) = ^{
    UIImage *cachedMemoryImage = [[ImageManager shared] imageFromMemoryCacheForKey:@"IMAGE_KEY"];
    UIImage *cachedDiskImage = [[ImageManager shared] imageFromDiskCacheForKey:@"IMAGE_KEY"];
    return cachedMemoryImage || cachedDiskImage;
};

[[ImageManager shared] purgeCacheAsync];

WAIT_WHILE(!cacheIsPurged(), 5.0, @"Failed to clean up image cache!");

}

WAIT_WHILE()
will stall current runloop while
!cacheIsPurged()
is
TRUE
and throw an
XCTFail()
or
STFail()
if exceeding time limit (5.0 seconds)

Under the hood

A simplified version of how the macro works could look like this

__block BOOL done = NO;
doSomethingAsynchronouslyWithBlock(^{
    done = YES;
});

while(!done) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; }

Effectively stalling the runloop until

done
is true. This does not block the main thread so you are still able to have callbacks on the main thread.

Advantages

  • Minimum code
  • Error thrown in the test. Since it is based on macro's the exception will not be thrown in some 3rd party implementation file further down the stack
  • Small library
  • Works perfectly with SenTestingKit and XCTest (could easily support more)
  • No known bugs or issues

Alternatives

You've got several alternatives like

If you've got other alternatives which should be listed here please let me know.

There is also a great thread on stack overflow http://stackoverflow.com/questions/4114083/ios-tests-specs-tdd-bdd-and-integration-acceptance-testing

Extensive description

This library or bundle enables you to do async test operations with asynchronous callbacks in your SenTestCase or XCTestCase. Works with GCD (Grand Central Dispatch), blocks, NSOperation and regular delegate callbacks.

Agens | Digital craftsmanship

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.