I am attempting to unit test using the below code. However, the test simply hangs at the wait portion. My test code is below. I'm new to iOS and to AFNetworking. Any help would be appreciated.
Things I Know: The method in USAPIConnection is being called. There is no success or failure method being called on TestController. The request to the rails api is working. (I know it returns a 200 OK code).
Things I Don't Know: Is the AFHTTPRequestOperationManager actually sending the request? Why is there no success of failure method being sent? Should this unit test be sufficient for testing?
XCTest Code
#import <XCTest/XCTest.h>
#import "USAPIConnection.h"
#import "Controller.h"
@interface TestController : NSObject <Controller>
@property bool done;
@end
@implementation TestController
-(void)asynchronousSuccessfulWithObject:(id)object type:(int)type{
NSLog(@"Object: %@", object);
XCTAssertNotNil(object,"@Should have returned JSON object: %s",__PRETTY_FUNCTION__);
_done = true;
}
-(void)asynchronousUnsuccessfulWithError:(NSError *)error type:(int)type{
XCTFail(@"Unsuccessful async call with error%s: %s",error,__PRETTY_FUNCTION__);
_done = true;
}
@end
@interface USAPIConnectionTests : XCTestCase
@end
@implementation USAPIConnectionTests
- (void)setUp
{
[super setUp];
NSLog(@"Beginning Test: %s",__PRETTY_FUNCTION__);
}
- (void)tearDown
{
NSLog(@"Ending Test: %s",__PRETTY_FUNCTION__);
[super tearDown];
}
- (void)testGetTeamById
{
TestController* testController = [[TestController alloc] init];
testController.done = false;
[USAPIConnection getTeamById:1 controller:testController];
int count = 0;
while(!testController.done && count < 10){
//Waiting
[NSThread sleepForTimeInterval:3.0];
count = count + 1;
}
if(count == 10){
XCTFail(@"Timed out: %s",__PRETTY_FUNCTION__);
}
}
@end
Method Called in USAPIConnection
+(void)getTeamById:(int)identity controller:(id<Controller>)controller{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFJSONResponseSerializer* serializer = [AFJSONResponseSerializer serializer];
serializer.acceptableContentTypes = [NSSet setWithObject:@"application/json"];
manager.responseSerializer = serializer;
[manager POST:[NSString stringWithFormat:@"http://%@/team/%D",baseURL,identity] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[controller asynchronousSuccessfulWithObject:responseObject type:TYPETEAMSBYNAME];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[controller asynchronousUnsuccessfulWithError:error type:TYPETEAMSBYNAME];
}];
}
Attempting changing the test method to the below. However, neither NSLog in the test controller ran.
- (void)testGetTeamById
{
TestController* testController = [[TestController alloc] init];
testController.done = false;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{[USAPIConnection getTeamById:1 controller:testController];});
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{NSLog(@"HELLO FROM ASYNC QUEUE");});
}
XCTest in Xcode 6 (not yet released at the time of writing) supports testing of asynchronous methods.
Here's a small snippet in Swift that shows how it may look like:
Suppose you have an asynchronous method with a completion function as parameter:
func doSomethingAsync(completion:(result: Int?, error: Int?) -> ())
Now, you want to test whether either this async function performs successfully, or you want test some code which you define in the continuation (the completion handler):
func testAsyncFunction() {
let expect = self.expectationWithDescription("completion handler called")
doSomethingAsync { (result, error) -> () in
if let value = result? {
println("Result: \(value)")
}
else {
println("Error: \(error!)")
}
expect.fulfill()
}
waitForExpectationsWithTimeout(1000, handler: nil)
}
You can read more about the new methods of XCTest self.expectationWithDescription:
fulfill
and waitForExpectationsWithTimeout:
in the headers of XCTest.
I'm unit testing for a while now with this new asynchronous testing facility. Just missing some functionality, e.g. having a method reject
alongside fulfill
with an optional string parameter for logging. IMO, it looks quite appealing and it works great so far. So, I really encourage you to take a look into the Xcode beta ;
In the meantime, you may find a "promise" library applicable to implement testing of asynchronous methods. I've suggested to utilize the RXPromise library (I'm the author) for Unit testing several times in this forum. ;)