2016-04-08 9 views
0

Ich versuche derzeit, einen benutzerdefinierten Delegaten für eine asynchrone dataTaskWithRequest über NSURLSession einzurichten. Ich habe das Protokoll eingerichtet und die Delegate-Methode implementiert, aber ich muss herausfinden, ob ich es richtig implementiert habe und wie ich es testen kann. Insbesondere möchte ich testen, ob der Delegat nach dem Aufruf etwas zurückgibt und mit einem Live-API-Aufruf testet. Ich habe versucht, über den hier vorgeschlagenen Ansatz zu testen (OCUnit test for protocols/callbacks/delegate in Objective-C), aber der Test schlägt fehl, wahrscheinlich, weil ich etwas vermisse oder den Async-Aufruf nicht berücksichtige. Der Code für die versuchte Delegiertenimplementierung und der Komponententest sind unten aufgeführt.Delegat für NSURLSession einrichten und Einheit testen

Delegierter Protokollerklärung:

#include "PtvApiPublic.h" 

#ifndef PtvApiDelegate_h 
#define PtvApiDelegate_h 

@class PtvApi; 
@protocol PtvApiDelegate <NSObject> 
    -(void) ptvApiHealthCheck: (PtvApi *) sender; 
@end 

#endif /* PtvApiDelegate_h */ 

Headerdatei:

#include "PtvApiDelegate.h" 

#ifndef PtvApi_h 
#define PtvApi_h 

@interface PtvApi : NSObject 
@property (nonatomic, weak) id <NSURLSessionDelegate> delegate; 
- (void)ptvApiHealthCheck; 
@end 

#endif /* PtvApi_h */ 

Snippet PtvApi.m

#import <Foundation/Foundation.h> 
#import <CommonCrypto/CommonHMAC.h> 
#import <CommonCrypto/CommonDigest.h> 
#import "PtvApiPublic.h" 
#import "PtvApiPrivate.h" 
#import "PtvApiDelegate.h" 

@implementation PtvApi 
@synthesize delegate; 

... 

- (void)ptvApiHealthCheck 
{ 
    NSString *fullUrl = [self GenerateRequestUrl]; 

    NSURLSession *apiSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:delegate delegateQueue:nil]; 
    NSURL *apiUrl = [NSURL URLWithString: fullUrl]; 
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:apiUrl]; 
    [apiSession dataTaskWithRequest:urlRequest]; 
} 

@end 

Unit-Test:

#import <XCTest/XCTest.h> 

#import "PtvApiPublic.h" 

@interface APIDelegateTests : XCTestCase <NSURLSessionDelegate> 
{ 
    PtvApi *testApi; 
    BOOL callbackInvoked; 
} 
@end 

@implementation APIDelegateTests 

- (void)setUp { 
    [super setUp]; 
    testApi = [[PtvApi alloc] init]; 
    testApi.delegate = self; 
} 

- (void)tearDown { 
    testApi.delegate = nil; 
    [super tearDown]; 
} 

- (void)testThatApiCallbackWorks { 
    [testApi ptvApiHealthCheck]; 

    XCTAssert(callbackInvoked, @"Delegate should return something, I think..."); 
} 
@end 
+1

I [schrieb einen Blog-Post] (http://swiftandpainless.com/an-easy-way-to-stub-nsurlsession/) darüber, wie ich NSURLSession testen. Vielleicht hilft das. – dasdom

+0

@dasdom Danke für den Link, ich werde darauf verweisen, wenn ich meine andere Swift App neu überarbeite. –

Antwort

1

Okay, ich habe es selbst mit Hilfe von Apples Dokumentation für NSURLSession und dem Blog unter http://www.infinite-loop.dk/blog/2011/04/unittesting-asynchronous-network-access/ herausgefunden. Ich habe es jetzt mit der Live-URL getestet. Ich werde die Antwort aktualisieren, wenn ich meinem Unit-Test API-Mocking hinzufüge und den Unit-Test robuster mache.

Die kurze davon ist, dass seine eigene NSURLSession Delegatmethoden hat, und in diesem Fall, in dem dataTaskWithRequest verwendet wird, kann ein NSURLSessionDataDelegate aufgebaut und verwendet werden, um die API Ergebnisse abzurufen.

Der Code für die Delegate-Deklaration ist größtenteils korrekt, ich musste nur NSURLSessionDelegate zu NSURLSessionDataDelegate in der Header-Datei ändern.

Der Komponententest erfordert ein wenig Setup, ist aber ansonsten ziemlich einfach. Dazu muss die Klasse mit dem Aufruf NSURLSession initialisiert werden, der Delegat des Objekts auf self gesetzt und eine Flag-Variable auf NO initialisiert werden. Die Flag-Variable wird auf YES gesetzt, wenn der Delegat aufgerufen wird, für den ich zunächst testen möchte. Der vollständig eingerichtete Komponententest ist unten aufgeführt.

@interface APIDelegateTests : XCTestCase <NSURLSessionDataDelegate> 
{ 
    PtvApi *testApi; 
    BOOL callbackInvoked; 
} 
@end 

@implementation APIDelegateTests 

- (void)setUp { 
    [super setUp]; 
    testApi = [[PtvApi alloc] init]; 
    testApi.delegate = self; 
    callbackInvoked = NO; 
} 

- (void)tearDown { 
    testApi.delegate = nil; 
    [super tearDown]; 
} 

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data 
{ 
    callbackInvoked = YES; 
} 

// Method is credit to Claus Brooch. 
// Retrieved from http://www.infinite-loop.dk/blog/2011/04/unittesting-asynchronous-network-access/ on 10/04/2016 
- (BOOL)waitForCompletion:(NSTimeInterval)timeoutSecs { 
    NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs]; 

    do { 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate]; 
     if([timeoutDate timeIntervalSinceNow] < 0.0) 
      break; 
    } while (!callbackInvoked); 

    return callbackInvoked; 
} 

- (void)testThatApiCallbackWorks { 
    [testApi ptvApiHealthCheck]; 

    XCTAssert([self waitForCompletion:30.0], @"Testing to see what happens here..."); 
} 
@end