Unit testing completion blocks in iOS - ios

I am trying to figure out how to write unit test for client backend code but I have not been successful so far. I am not so experience with unit testing so I read This, This, andThis
and read some similar questions to what I am asking, but I have not been completely figure out how I should be writing unit tests for the client backend.
- (void)testThatItGetsAllUsers
{
// given
XCTestExpectation *expectation = [self expectationWithDescription:#" fetch all users"];
// when
[[Backend sharedInstance] getAllUsers:^(NSArray * arr) {
XCTAssertNotNil(arr);
[expectation fulfill];
}andFailure:^(NSError * err) {
XCTAssert((err != nil), #"get all users request failed with error:\t%#", err);
}];
[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
// request not successfull
XCTAssert((error != nil), #"get all users from server did not return any data:\t%#", error);
}];
// then
}
It would be really helpful if someone can point out what I am doing wrong and any additional knowledge is appreciated!

You need to modify waitForExpectationsWithTimeout as follow
[self waitForExpectationsWithTimeout:INT16_MAX handler:^(NSError *error) {
BOOL flag = (error == nil);
XCTAssert(flag, #"get all users from server did not return any data:\t%#", error);
}];
And also add to your andFailure block [expectation fulfill] like this:
andFailure:^(NSError * err) {
[expectation fulfill];
XCTAssert((err != nil), #"get all users request failed with error:\t%#", err);
}];
If you want to know more about async testing take a look at nshipster blog. There is a nice explanation of XCTestExpectation along with example.
By following one of John Reid videos I have wrote small project which uses Mocking and DI technics to test networking calls.

Related

nested callback hell in objective c

I am now working on an app that works with BLE, Backend server and location. I am facing a problem which I am not sure how to get out of which is what people call "Callback hell". The entire CoreBluetooth framework in iOS is based on a delegate pattern, which until you can use the CBPeripheral has to go to at least 3 callbacks:
DidConnectToPeripheral
DidDiscoverServices
DidDiscoverCharacteristics
But in fact there could be many more, and every action you take with the device will come back as a callback to one of those functions. Now when I want to "Rent" this ble product, I must connect to it, after connecting send a requests to the server and get the user's current location, after that all happens I have to write a value in the bluetooth device and get confirmation. This would not be so difficult, but unfortunately each and every one of those stages is failable, so error handling needs to be added. Not to mention implementing timeout.
I am sure I am not the only one to approach such issues so I looked around and I found 2 things that might help:
the Advanced NSOperations talk in the wwdc 2015, but after trying for 4 days to make it work, it seems like the code is too buggy.
Promisekit but I couldn't find a way to wrap CoreBluetooth.
How are people with even more complicated apps deal with this? in swift or objc.
Some sample problematic code:
-(void)startRentalSessionWithLock:(DORLock *)lock timeOut:(NSTimeInterval)timeout forSuccess:(void (^)(DORRentalSession * session))successBlock failure:(failureBlock_t)failureBlock{
//we set the block to determine what happens
NSAssert(lock.peripheral, #"lock has to have peripheral to connect to");
if (!self.rentalSession) {
self.rentalSession = [[DORRentalSession alloc] initWithLock:nil andSessionDict:#{} active:NO];
}
self.rentalSession.lock = lock;
[self connectToLock:self.rentalSession.lock.peripheral timeOut:timeout completionBlock:^(CBPeripheral *peripheral, NSError *error) {
self.BTConnectionCompleted = nil;
if (!error) {
[[INTULocationManager sharedInstance] requestLocationWithDesiredAccuracy:INTULocationAccuracyHouse timeout:1 delayUntilAuthorized:YES block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess || status == INTULocationStatusTimedOut) {
[self startServerRentalForSessionLockWithUserLocation:currentLocation.coordinate forSuccess:^(DORRentalSession *session) {
if (self.rentalSession.lock.peripheral && self.rentalSession.lock.peripheral.state == CBPeripheralStateConnected) {
[self.rentalSession.lock.peripheral setNotifyValue:YES forCharacteristic:self.rentalSession.lock.charectaristics.sensorCharacteristic];
}else{
//shouldnt come here
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.rentalSession.lock.peripheral.state == CBPeripheralStateConnected) {
!self.rentalSession.lock.open ? [self sendUnlockBLECommandToSessionLock] : nil;
if (successBlock) {
successBlock(session);
}
}else{
[self endCurrentRentalSessionWithLocation:self.rentalSession.lock.latLng andPositionAcc:#(1) Success:^(DORRentalSession *session) {
if (failureBlock) {
failureBlock([[NSError alloc] initWithDomain:DonkeyErrorDomain code:46 userInfo:#{NSLocalizedDescriptionKey:#"Could't connect to lock"}],200);
}
} failure:^(NSError *error, NSInteger httpCode) {
if (failureBlock) {
failureBlock([[NSError alloc] initWithDomain:DonkeyErrorDomain code:45 userInfo:#{NSLocalizedDescriptionKey:#"fatal error"}],200);
}
}];
}
});
} failure:^(NSError *error, NSInteger httpCode) {
if (failureBlock) {
failureBlock(error,httpCode);
}
}];
}else{
NSError *gpsError = [self donkeyGPSErrorWithINTULocationStatus:status];
if (failureBlock) {
failureBlock(gpsError,200);
}
}
}];
}else{
if (failureBlock) {
failureBlock(error,200);
}
}
}];
}
To get rid of this nested calls you can use GCD group + serial execution queue:
dispatch_queue_t queue = ddispatch_queue_create("com.example.queue", NULL);
dispatch_group_t group = dispatch_group_create();
// Add a task to the group
dispatch_group_async(group, queue, ^{
// Some asynchronous work
});
// Make dispatch_group_async and dispatch_group_sync calls here
// Callback to be executed when all scheduled tasks are completed.
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
// Do smth when everything has finished
});
// wait for all tasks to complete
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
The other solution based on GCD groups is described here

Asynchronous Performance Tests with XCTest

I have started to explore the new XCTest APIs for asynchronous and performance testing. In isolation, the Apple examples from WWMC work well, but I have been unable to figure out how to combine them. The best I have been able to come up with is the following, but I receive the following error when it runs:
API violation - call made to wait without any expectations having been set.
XCTestExpectation *clsQueryReturnedExpectation = [self expectationWithDescription:#"clsQuery returned"];
PFCLSClient *theClient = [[PFCLSClient alloc] init];
[self measureMetrics:#[XCTPerformanceMetric_WallClockTime] automaticallyStartMeasuring:YES forBlock: ^{
[theClient getStructureOfType:clsImageTypeSVG ForID:idString success: ^(NSDictionary *structureInfo) {
[clsQueryReturnedExpectation fulfill];
} failure: ^(NSError *error) {
XCTFail();
[clsQueryReturnedExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler: ^(NSError *error) {
[self stopMeasuring];
}];
}];
Has anyone been able to accomplish something similar?
Thx
With some help from Apple, I have a solution. Silly oversight on my part as this is very easy to solve. To get to work, all you need to do is put the creating of the expectation object (clsQueryReturnedExpectation) inside the measureMetrics block so it is created afresh each time the performance test is run.
PFCLSClient *theClient = [[PFCLSClient alloc] init];
[self measureMetrics:#[XCTPerformanceMetric_WallClockTime] automaticallyStartMeasuring:YES forBlock: ^{
XCTestExpectation *clsQueryReturnedExpectation = [self expectationWithDescription:#"clsQuery returned"];
[theClient getStructureOfType:clsImageTypeSVG ForID:idString success: ^(NSDictionary *structureInfo) {
[clsQueryReturnedExpectation fulfill];
} failure: ^(NSError *error) {
XCTFail();
[clsQueryReturnedExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler: ^(NSError *error) {
[self stopMeasuring];
}];
}];

XCTest and asynchronous testing in Xcode 6

So Apple said in the release note of Xcode 6 that we can now do asynchronous testing directly with XCTest.
Anyone knows how to do it using Xcode 6 Beta 3 (Using objective-C or Swift)? I don't want the known semaphore method, but the new Apple way.
I searched into the released note and more but I found nothing. The XCTest header is not very explicit either.
Obj-C example:
- (void)testAsyncMethod
{
//Expectation
XCTestExpectation *expectation = [self expectationWithDescription:#"Testing Async Method Works!"];
[MyClass asyncMethodWithCompletionBlock:^(NSError *error, NSHTTPURLResponse *httpResponse, NSData *data) {
if(error)
{
NSLog(#"error is: %#", error);
}else{
NSInteger statusCode = [httpResponse statusCode];
XCTAssertEqual(statusCode, 200);
[expectation fulfill];
}
}];
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
if(error)
{
XCTFail(#"Expectation Failed with error: %#", error);
}
}];
}
The sessions video is perfect, basically you want to do something like this
func testFetchNews() {
let expectation = self.expectationWithDescription("fetch posts")
Post.fetch(.Top, completion: {(posts: [Post]!, error: Fetcher.ResponseError!) in
XCTAssert(true, "Pass")
expectation.fulfill()
})
self.waitForExpectationsWithTimeout(5.0, handler: nil)
}
Session 414 covers async testing in Xcode6
https://developer.apple.com/videos/wwdc/2014/#414
How I did in swift2
Step 1: define expectation
let expectation = self.expectationWithDescription("get result bla bla")
Step 2: tell the test to fulfill expectation right below where you capture response
responseThatIGotFromAsyncRequest = response.result.value
expectation.fulfill()
Step 3: Tell the test to wait till the expectation is fulfilled
waitForExpectationsWithTimeout(10)
STep 4: make assertion after async call is finished
XCTAssertEqual(responseThatIGotFromAsyncRequest, expectedResponse)

Is Bolts framework[Parse+Facebook] need to use parse webservice?

I already post question How to use Bolts Framework[Facebook+Parse] but Now I've question, Must I use parse webservice if I want to use Bolts-framework?
They provide sample code like below which related(saveAsync:) to Parse webservice. But I've seen in this line "Using these libraries does not require using any Parse services. Nor do they require having a Parse or Facebook developer account" in Boltss' github
[[object saveAsync:obj] continueWithBlock:^id(BFTask *task) {
if (task.isCancelled) {
// the save was cancelled.
} else if (task.error) {
// the save failed.
} else {
// the object was saved successfully.
SaveResult *saveResult = task.result;
}
return nil;
}];
Now I get confusion, Is bolts framework need to use parse webservice?
Note: Don't ask where do you want to use Bolts-framework. see my first line of this question.
Surely it doesn't need Parse webservice. I've the same difficulty in implementing my own task and I'm studying this framework. Take a look at BoltsTest code: you can find some useful code.
I'm trying some experiments in a sample project (https://github.com/giaesp/BoltsFrameworkSample). Basically you need to define your own method returning a BFTask. Here a simple excerpt.
- (BFTask*) parseHTML:(NSURL*)url searchString:(NSString*)searchString {
BFTaskCompletionSource * tcs = [BFTaskCompletionSource taskCompletionSource];
NSURLRequest * request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
NSURLResponse * response;
NSError * error;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
NSString * receivedData = [NSString stringWithUTF8String:[returnData bytes]];
NSUInteger occurrences = [self countOccurencesOfString:#"iOS" inputString:receivedData];
[tcs setResult:[NSNumber numberWithInt:occurrences]];
}
else {
[tcs setError:error];
}
return tcs.task;
}
Then you can use your method as the docs explains and check the task status.
[[self parseHTML:[NSURL URLWithString:#"http://www.stackoverflow.com"]] continueWithBlock:^id(BFTask *task) {
if (task.isCancelled) {
// the task was cancelled
} else if (task.error) {
// the task failed
} else {
// the task completes
}
return nil;
}];
I know it's been a while since this question was asked but as mani wanted to know if you could use Bolts framework with AFNetworking as well i want to add a quick example that shows usage.
It's written in swift and really just plain and simple.
func taskWithPath(path: String) -> BFTask {
let task = BFTaskCompletionSource()
AFHTTPRequestOperationManager().GET(path, parameters: nil, success: { (operation, response) in
task.setResult(response)
}) { (operation, error) -> Void in
task.setError(error)
}
return task.task
}
Hope this helps :)
The idea with Bolts is to encapsulate any operation using a BFTask. You don't necessarily have to wrap the operation in a method, but it's a good way to imagine how you should structure your code:
- (BFTask*) asynchronousImageProcessOperation;
- (BFTask*) asynchronousNetworkOperation;
...and all of these would follow a similar pattern:
- (BFTask*) asynchronousNetworkOperation {
BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource];
// ... here's the code that does some asynchronous operation on another thread/queue
[someAsyncTask completeWithBlock:^(id response, NSError *error) {
error ? [source setError:error] : [source setResult:response];
}
return task;
}
The beauty of it is that you can them string these tasks together in some way. For example, if you needed to process an image and then upload it, you could do:
[[object methodReturnImageProcessingTask] continueWithBlock:^(BFTask *task) {
[[anotherObject imageUploadTaskForImage:task.result] continueWithBlock:^(BFTask *task) {
self.label.text = #"Processing and image complete";
}]
}]
Of course you could also encapsulate that two-stage task in its own task:
- (BFTask*) processAndUploadImage:(UIImage* image);
Typing from memory here. It's the sequencing and grouping that's really powerful. Great framework.

Testing asynchronous call in unit test in iOS

I am facing a problem while unit testing an asynchronous call in iOS. (Although it is working fine in view controllers.)
Has anyone faced this issue before? I have tried using a wait function but I'm still facing the same problem.
Please suggest an example of a good way to do this.
You'll need to spin the runloop until your callback is invoked. Make sure that it gets invoked on the main queue, though.
Try this:
__block BOOL done = NO;
doSomethingAsynchronouslyWithBlock(^{
done = YES;
});
while(!done) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
You can also use a semaphore (example below), but I prefer to spin the runloop to allow asynchronous blocks dispatched to the main queue to be processed.
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
doSomethingAsynchronouslyWithBlock(^{
//...
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
Here is Apple's description of native support for async testing.
TL;DR manual:
Look at XCTextCase+AsynchronousTesting.h
There is special class XCTestExpectation with only one public method: - (void)fulfill;
You should init instance of this class and in success case call fulfill method. Otherwise your test will fail after timeout that you specify in that method:
- (void)waitForExpectationsWithTimeout:(NSTimeInterval)timeout handler:(XCWaitCompletionHandler)handlerOrNil;
Example:
- (void)testAsyncMethod
{
//Expectation
XCTestExpectation *expectation = [self expectationWithDescription:#"Testing Async Method Works Correctly!"];
[MyClass asyncMethodWithCompletionBlock:^(NSError *error) {
if(error)
NSLog(#"error is: %#", error);
else
[expectation fulfill];
}];
//Wait 1 second for fulfill method called, otherwise fail:
[self waitForExpectationsWithTimeout:1 handler:^(NSError *error) {
if(error)
{
XCTFail(#"Expectation Failed with error: %#", error);
}
}];
}
I think many of the suggested solutions in this post has the problem that if the asynchronous operation does not complete the "done" flag is never set, and the test will hang forever.
I have successfully used this approach in many of my test.
- (void)testSomething {
__block BOOL done = NO;
[obj asyncMethodUnderTestWithCompletionBlock:^{
done = YES;
}];
XCTAssertTrue([self waitFor:&done timeout:2],
#"Timed out waiting for response asynch method completion");
}
- (BOOL)waitFor:(BOOL *)flag timeout:(NSTimeInterval)timeoutSecs {
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
if ([timeoutDate timeIntervalSinceNow] < 0.0) {
break;
}
}
while (!*flag);
return *flag;
}
Since Xcode 6 this built in to XCTest as a category:
See https://stackoverflow.com/a/24705283/88164
Here's another alternative, XCAsyncTestCase, that works well with OCMock if you need to use it. It's based on GHUnit's async tester, but is uses the regular XCTest framework instead.
Fully compatible with Xcode Bots.
https://github.com/iheartradio/xctest-additions
Usage is the same, just import and subclass XCAsyncTestCase.
#implementation TestAsync
- (void)testBlockSample
{
[self prepare];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
sleep(1.0);
[self notify:kXCTUnitWaitStatusSuccess];
});
// Will wait for 2 seconds before expecting the test to have status success
// Potential statuses are:
// kXCTUnitWaitStatusUnknown, initial status
// kXCTUnitWaitStatusSuccess, indicates a successful callback
// kXCTUnitWaitStatusFailure, indicates a failed callback, e.g login operation failed
// kXCTUnitWaitStatusCancelled, indicates the operation was cancelled
[self waitForStatus:kXCTUnitWaitStatusSuccess timeout:2.0];
}
AGAsyncTestHelper is a C macro for writing unit tests with asynchronous operations and works with both SenTestingKit and XCTest.
Simple and to the point
- (void)testAsyncBlockCallback
{
__block BOOL jobDone = NO;
[Manager doSomeOperationOnDone:^(id data) {
jobDone = YES;
}];
WAIT_WHILE(!jobDone, 2.0);
}
Sam Brodkin already gave the right answer.
Just to make the answer looks better at first sight, I bring the sample code here.
Use XCTestExpectation.
// Test that the document is opened. Because opening is asynchronous,
// use XCTestCase's asynchronous APIs to wait until the document has
// finished opening.
- (void)testDocumentOpening
{
// Create an expectation object.
// This test only has one, but it's possible to wait on multiple expectations.
XCTestExpectation *documentOpenExpectation = [self expectationWithDescription:#"document open"];
NSURL *URL = [[NSBundle bundleForClass:[self class]]
URLForResource:#"TestDocument" withExtension:#"mydoc"];
UIDocument *doc = [[UIDocument alloc] initWithFileURL:URL];
[doc openWithCompletionHandler:^(BOOL success) {
XCTAssert(success);
// Possibly assert other things here about the document after it has opened...
// Fulfill the expectation-this will cause -waitForExpectation
// to invoke its completion handler and then return.
[documentOpenExpectation fulfill];
}];
// The test will pause here, running the run loop, until the timeout is hit
// or all expectations are fulfilled.
[self waitForExpectationsWithTimeout:1 handler:^(NSError *error) {
[doc closeWithCompletionHandler:nil];
}];
}
you can use async api calling in swift like this
private let serverCommunicationManager : ServerCommunicationManager = {
let instance = ServerCommunicationManager()
return instance
}()
var expectation:XCTestExpectation?
func testAsyncApiCall() {
expectation = self.expectation(description: "async request")
let header = ["Authorization":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImQ4MmY1MTcxNzI4YTA5MjI3NWIzYWI3OWNkOTZjMGExOTI4MmM2NDEyZjMyYWQzM2ZjMzY4NmU2MjlhOWY2YWY1NGE0MDI4MmZiNzY2NWQ3In0.eyJhdWQiOiIxIiwianRpIjoiZDgyZjUxNzE3MjhhMDkyMjc1YjNhYjc5Y2Q5NmMwYTE5MjgyYzY0MTJmMzJhZDMzZmMzNjg2ZTYyOWE5ZjZhZjU0YTQwMjgyZmI3NjY1ZDciLCJpYXQiOjE1MDg4MjU1NTEsIm5iZiI6MTUwODgyNTU1MSwiZXhwIjoxNTQwMzYxNTUxLCJzdWIiOiIiLCJzY29wZXMiOltdfQ.osoMQgiY7TY7fFrh5r9JRQLQ6AZhIuEbrIvghF0VH4wmkqRUE6oZWjE5l0jx1ZpXsaYUhci6EDngnSTqs1tZwFTQ3srWxdXns2R1hRWUFkAN0ri32W0apywY6BrahdtiVZa9LQloD1VRMT1_QUnljMXKsLX36gXUsNGU6Bov689-bCbugK6RC3n4LjFRqJ3zD9gvkRaODuOQkqsNlS50b5tLm8AD5aIB4jYv3WQ4-1L74xXU0ZyBTAsLs8LOwvLB_2B9Qdm8XMP118h7A_ddLo9Cyw-WqiCZzeZPNcCvjymNK8cfli5_LZBOyjZT06v8mMqg3zszWzP6jOxuL9H1JjBF7WrPpz23m7dhEwa0a-t3q05tc1RQRUb16W1WhbRJi1ufdMa29uyhX8w_f4fmWdAnBeHZ960kjCss98FA73o0JP5F0GVsHbyCMO-0GOHxow3-BqyPOsmcDrI4ay006fd-TJk52Gol0GteDgdntvTMIrMCdG2jw8rfosV6BgoJAeRbqvvCpJ4OTj6DwQnV-diKoaHdQ8vHKe-4X7hbYn_Bdfl52gMdteb3_ielcVXIaHmQ-Dw3E2LSVt_cSt4tAHy3OCd7WORDY8uek4Paw8Pof0OiuqQ0EB40xX5hlYqZ7P_tXpm-W-8ucrIIxgpZb0uh-wC3EzBGPjpPD2j9CDo"]
serverCommunicationManager.sendServerRequest(httpMethodType: .get, baseURL: "http://192.168.2.132:8000/api/v1/user-role-by-company-id/2", param: nil, header: header) { (isSuccess, msg , response) in
if isSuccess
{
let array = response as! NSArray
if array.count == 8
{
XCTAssertTrue(true)
self.expectation?.fulfill()
}
else
{
XCTAssertFalse(false)
XCTFail("array count fail")
}
}
}
waitForExpectations(timeout: 5) { (error) in
if let error = error{
XCTFail("waiting with error: \(error.localizedDescription)")
}
}
}
I suggest you should have a look on the tests of Facebook-ios-sdk. It's a good example of how to test async unit test on iOS, though personally I think async tests should be break into sync tests.
FBTestBlocker: a blocker that prevent current thread exits with specified timeout. You can drag and drop this to your project, but you need to remove OCMock related stuff if you don't have that in you project.
FBTestBlocker.h
FBTestBlocker.m
FBURLConnectionTests: test examples you should look at.
FBURLConnectionTests.h
FBURLConnectionTests.m
This code snippet should give you some idea
- (void)testExample
{
FBTestBlocker *_blocker = [[FBTestBlocker alloc] initWithExpectedSignalCount:1];
__block BOOL excuted = NO;
[testcase test:^(BOOL testResult) {
XCTAssert(testResult, #"Should be true");
excuted = YES;
[_blocker signal];
}];
[_blocker waitWithTimeout:4];
XCTAssertTrue(excuted, #"Not executed");
}
Try KIWI framework. It's powerful and might help you with other kinds of tests.
I recommend you connection semaphore + runloop, i also wrote method which take block:
// Set the flag to stop the loop
#define FLEND() dispatch_semaphore_signal(semaphore);
// Wait and loop until flag is set
#define FLWAIT() WAITWHILE(dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
// Macro - Wait for condition to be NO/false in blocks and asynchronous calls
#define WAITWHILE(condition) \
do { \
while(condition) { \
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; \
} \
} while(0)
method:
typedef void(^FLTestAsynchronousBlock)(void(^completion)(void));
void FLTestAsynchronous(FLTestAsynchronousBlock block) {
FLSTART();
block(^{
FLEND();
});
FLWAIT();
};
and call
FLTestAsynchronous(^(void(^completion)()){
[networkManager signOutUser:^{
expect(networkManager.currentUser).to.beNil();
completion();
} errorBlock:^(NSError *error) {
expect(networkManager.currentUser).to.beNil();
completion();
}];
});
If you are using XCode 6, you can test async network calls like this:
XCTest and asynchronous testing in Xcode 6

Resources