diff --git a/OHHTTPStubs/OHHTTPStubs.h b/OHHTTPStubs/OHHTTPStubs.h index 6303710a..21da5308 100644 --- a/OHHTTPStubs/OHHTTPStubs.h +++ b/OHHTTPStubs/OHHTTPStubs.h @@ -34,7 +34,11 @@ typedef BOOL(^OHHTTPStubsTestBlock)(NSURLRequest* request); typedef OHHTTPStubsResponse*(^OHHTTPStubsResponseBlock)(NSURLRequest* request); -typedef id OHHTTPStubsID; + +@protocol OHHTTPStubsDescriptor +/*! Arbitrary name that you can set and get to describe your stub. Use it as your own convenience. */ +@property(nonatomic, strong) NSString* name; +@end //////////////////////////////////////////////////////////////////////////////// #pragma mark - Interface @@ -46,18 +50,23 @@ typedef id OHHTTPStubsID; #pragma mark - Class Methods /*! Dedicated method to add a stub - @param testBlock Block that should return `YES` if the request passed as parameter should be stubbed with the response block, `NO` if it should hit the real world (or be managed by another stub). + @param testBlock Block that should return `YES` if the request passed as parameter should be stubbed with the response block, + and `NO` if it should hit the real world (or be managed by another stub). @param responseBlock Block that will return the `OHHTTPStubsResponse` (response to use for stubbing) corresponding to the given request - @return an opaque object that uniquely identifies the stub and can be later used to remove it with `removeStub:` + @return a stub descriptor that uniquely identifies the stub and can be later used to remove it with `removeStub:`. + @note The returned stub descriptor is retained (`__strong` reference) by `OHHTTPStubs` until it is removed + (with one of the `removeStub:`/`removeLastStub`/`removeAllStubs` methods); it is thus recommended to + keep it in a `__weak` storage (and not `__strong`) in your app code, to let the stub descriptor be destroyed + and let the variable go back to `nil` automatically when the stub is removed. */ -+(OHHTTPStubsID)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock - withStubResponse:(OHHTTPStubsResponseBlock)responseBlock; ++(id)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock + withStubResponse:(OHHTTPStubsResponseBlock)responseBlock; /*! Remove a stub from the list of stubs - @param stubID the opaque object that has been returned when adding the stub using `stubRequestsPassingTest:withStubResponse:` + @param stubDesc the stub descriptor that has been returned when adding the stub using `stubRequestsPassingTest:withStubResponse:` @return `YES` if the stub has been successfully removed, `NO` if the parameter was not a valid stub identifier */ -+(BOOL)removeStub:(OHHTTPStubsID)stubID; ++(BOOL)removeStub:(id)stubDesc; /*! Remove the last added stub from the stubs list */ +(void)removeLastStub; @@ -70,6 +79,20 @@ typedef id OHHTTPStubsID; */ +(void)setEnabled:(BOOL)enabled; +#pragma mark - Debug Methods + +/*! List all the installed stubs + @return An array of id objects currently installed. Useful for debug. + */ ++(NSArray*)allStubs; + +/*! Setup a block to be called each time a stub is triggered. + + Useful if you want to log all your requests being stubbed for example and see which stub was used to respond to each request. + @param block The block to call each time a request is being stubbed by OHHTTPStubs. Set it to `nil` to do nothing. Defaults is `nil`. + */ ++(void)onStubActivation:( void(^)(NSURLRequest* request, id stub) )block; + @end @@ -80,7 +103,9 @@ typedef id OHHTTPStubsID; @interface OHHTTPStubs (Deprecated) -typedef id OHHTTPStubsRequestHandlerID __attribute__((deprecated("Use OHHTTPStubsID instead"))); +typedef id OHHTTPStubsRequestHandlerID __deprecated_msg("Use OHHTTPStubsDescriptor* instead"); +typedef id OHHTTPStubsID __deprecated_msg("Use id instead"); + /*! @warning This method is deprecated @@ -92,7 +117,7 @@ typedef id OHHTTPStubsRequestHandlerID __attribute__((deprecated("Use OHHTTPStub @return an opaque object that uniquely identifies the handler and can be later used to remove it with `removeRequestHandler:` */ +(OHHTTPStubsRequestHandlerID)addRequestHandler:(OHHTTPStubsResponse*(^)(NSURLRequest* request, BOOL onlyCheck))handler -__attribute__((deprecated("Use stubRequestsPassingTest:withStubResponse: instead"))); +__deprecated_msg("Use stubRequestsPassingTest:withStubResponse: instead"); /*! Remove a request handler from the list of stubs @param handlerID the opaque object that has been returned when adding the handler using `stubRequestsPassingTest:withStubResponse:` @@ -100,14 +125,14 @@ __attribute__((deprecated("Use stubRequestsPassingTest:withStubResponse: instead @return `YES` if the request handler has been successfully removed, `NO` if the parameter was not a valid handler identifier */ +(BOOL)removeRequestHandler:(OHHTTPStubsRequestHandlerID)handlerID -__attribute__((deprecated("Use removeStub: instead"))); +__deprecated_msg("Use removeStub: instead"); /*! Remove the last added request handler from the stubs list */ +(void)removeLastRequestHandler -__attribute__((deprecated("Use removeLastStub instead"))); +__deprecated_msg("Use removeLastStub instead"); /*! Remove all the requests handlers from the stubs list. */ +(void)removeAllRequestHandlers -__attribute__((deprecated("Use removeAllStubs instead"))); +__deprecated_msg("Use removeAllStubs instead"); @end diff --git a/OHHTTPStubs/OHHTTPStubs.m b/OHHTTPStubs/OHHTTPStubs.m index e1485d2f..92f7de41 100644 --- a/OHHTTPStubs/OHHTTPStubs.m +++ b/OHHTTPStubs/OHHTTPStubs.m @@ -36,20 +36,51 @@ #pragma mark - Types & Constants @interface OHHTTPStubsProtocol : NSURLProtocol @end -typedef OHHTTPStubsResponse*(^OHHTTPStubsRequestHandler)(NSURLRequest* request, BOOL onlyCheck); static NSTimeInterval const kSlotTime = 0.25; // Must be >0. We will send a chunk of the data from the stream each 'slotTime' seconds //////////////////////////////////////////////////////////////////////////////// -#pragma mark - Private Interface +#pragma mark - Private Interfaces @interface OHHTTPStubs() + (instancetype)sharedInstance; -@property(atomic, strong) NSMutableArray* requestHandlers; +@property(atomic, copy) NSMutableArray* stubDescriptors; +@property(atomic, copy) void (^onStubActivationBlock)(NSURLRequest*, id); @end +@interface OHHTTPStubsDescriptor : NSObject +@property(atomic, copy) OHHTTPStubsTestBlock testBlock; +@property(atomic, copy) OHHTTPStubsResponseBlock responseBlock; +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - OHHTTPStubsDescriptor Implementation + +@implementation OHHTTPStubsDescriptor + +@synthesize name = _name; + ++(instancetype)stubDescriptorWithTestBlock:(OHHTTPStubsTestBlock)testBlock + responseBlock:(OHHTTPStubsResponseBlock)responseBlock +{ + OHHTTPStubsDescriptor* stub = [OHHTTPStubsDescriptor new]; + stub.testBlock = testBlock; + stub.responseBlock = responseBlock; + return stub; +} + +-(NSString*)description +{ + return [NSString stringWithFormat:@"<%@ %p : %@>", self.class, self, self.name]; +} + +@end + + + + //////////////////////////////////////////////////////////////////////////////// -#pragma mark - Implementation +#pragma mark - OHHTTPStubs Implementation @implementation OHHTTPStubs @@ -76,7 +107,7 @@ - (id)init self = [super init]; if (self) { - _requestHandlers = [NSMutableArray array]; + _stubDescriptors = [NSMutableArray array]; [self.class setEnabled:YES]; } return self; @@ -90,34 +121,26 @@ - (void)dealloc //////////////////////////////////////////////////////////////////////////////// #pragma mark - Public class methods -+(OHHTTPStubsID)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock - withStubResponse:(OHHTTPStubsResponseBlock)responseBlock ++(id)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock + withStubResponse:(OHHTTPStubsResponseBlock)responseBlock { - return [self.sharedInstance addRequestHandler:^OHHTTPStubsResponse *(NSURLRequest *request, BOOL onlyCheck) - { - BOOL shouldStub = testBlock ? testBlock(request) : YES; - if (onlyCheck) - { - return shouldStub ? (OHHTTPStubsResponse*)@"DummyStub" : (OHHTTPStubsResponse*)nil; - } - else - { - return (responseBlock && shouldStub) ? responseBlock(request) : nil; - } - }]; + OHHTTPStubsDescriptor* stub = [OHHTTPStubsDescriptor stubDescriptorWithTestBlock:testBlock + responseBlock:responseBlock]; + [OHHTTPStubs.sharedInstance addStub:stub]; + return stub; } -+(BOOL)removeStub:(OHHTTPStubsID)stubID ++(BOOL)removeStub:(id)stubDesc { - return [self.sharedInstance removeRequestHandler:stubID]; + return [OHHTTPStubs.sharedInstance removeStub:stubDesc]; } +(void)removeLastStub { - [self.sharedInstance removeLastRequestHandler]; + [OHHTTPStubs.sharedInstance removeLastStub]; } +(void)removeAllStubs { - [self.sharedInstance removeAllRequestHandlers]; + [OHHTTPStubs.sharedInstance removeAllStubs]; } +(void)setEnabled:(BOOL)enabled @@ -130,66 +153,77 @@ +(void)setEnabled:(BOOL)enabled else if (!enabled && currentEnabledState) { // Force instanciate sharedInstance to avoid it being created later and this turning setEnabled to YES again - (void)self.sharedInstance; // This way if we call [setEnabled:NO] before any call to sharedInstance it will be kept disabled + (void)OHHTTPStubs.sharedInstance; // This way if we call [setEnabled:NO] before any call to sharedInstance it will be kept disabled [NSURLProtocol unregisterClass:OHHTTPStubsProtocol.class]; } currentEnabledState = enabled; } ++(NSArray*)allStubs +{ + return [OHHTTPStubs.sharedInstance stubDescriptors]; +} + ++(void)onStubActivation:( void(^)(NSURLRequest* request, id stub) )block +{ + [OHHTTPStubs.sharedInstance setOnStubActivationBlock:block]; +} + + + //////////////////////////////////////////////////////////////////////////////// #pragma mark - Private instance methods --(OHHTTPStubsID)addRequestHandler:(OHHTTPStubsRequestHandler)handler +-(void)addStub:(OHHTTPStubsDescriptor*)stubDesc { - OHHTTPStubsRequestHandler handlerCopy = [handler copy]; - @synchronized(_requestHandlers) + @synchronized(_stubDescriptors) { - [_requestHandlers addObject:handlerCopy]; + [_stubDescriptors addObject:stubDesc]; } - return handlerCopy; } --(BOOL)removeRequestHandler:(OHHTTPStubsID)stubID +-(BOOL)removeStub:(id)stubDesc { BOOL handlerFound = NO; - @synchronized(_requestHandlers) + @synchronized(_stubDescriptors) { - handlerFound = [self.requestHandlers containsObject:stubID]; - [_requestHandlers removeObject:stubID]; + handlerFound = [_stubDescriptors containsObject:stubDesc]; + [_stubDescriptors removeObject:stubDesc]; } return handlerFound; } --(void)removeLastRequestHandler + +-(void)removeLastStub { - @synchronized(_requestHandlers) + @synchronized(_stubDescriptors) { - [_requestHandlers removeLastObject]; + [_stubDescriptors removeLastObject]; } } --(void)removeAllRequestHandlers +-(void)removeAllStubs { - @synchronized(_requestHandlers) + @synchronized(_stubDescriptors) { - [_requestHandlers removeAllObjects]; + [_stubDescriptors removeAllObjects]; } } -//////////////////////////////////////////////////////////////////////////////// -#pragma mark - Private methods - -- (OHHTTPStubsResponse*)responseForRequest:(NSURLRequest*)request onlyCheck:(BOOL)onlyCheck +- (OHHTTPStubsDescriptor*)firstStubPassingTestForRequest:(NSURLRequest*)request { - OHHTTPStubsResponse* response = nil; - @synchronized(_requestHandlers) + OHHTTPStubsDescriptor* foundStub = nil; + @synchronized(_stubDescriptors) { - for(OHHTTPStubsRequestHandler handler in _requestHandlers.reverseObjectEnumerator) + for(OHHTTPStubsDescriptor* stub in _stubDescriptors.reverseObjectEnumerator) { - response = handler(request, onlyCheck); - if (response) break; + if (stub.testBlock(request)) + { + foundStub = stub; + break; + } } } - return response; + return foundStub; } @end @@ -201,11 +235,18 @@ - (OHHTTPStubsResponse*)responseForRequest:(NSURLRequest*)request onlyCheck:(BOO #pragma mark - Deprecated Methods (will be removed in 3.0) /*! @name Deprecated Methods */ +typedef OHHTTPStubsResponse*(^OHHTTPStubsRequestHandler)(NSURLRequest* request, BOOL onlyCheck) __deprecated; + @implementation OHHTTPStubs (Deprecated) +(OHHTTPStubsRequestHandlerID)addRequestHandler:(OHHTTPStubsRequestHandler)handler { - return [self.sharedInstance addRequestHandler:handler]; + return [OHHTTPStubsDescriptor stubDescriptorWithTestBlock:^BOOL(NSURLRequest *request) + { + return (handler(request, YES) != nil); + } responseBlock:^OHHTTPStubsResponse *(NSURLRequest *request) { + return handler(request, NO); + }]; } +(BOOL)removeRequestHandler:(OHHTTPStubsRequestHandlerID)handler @@ -242,7 +283,7 @@ @implementation OHHTTPStubsProtocol + (BOOL)canInitWithRequest:(NSURLRequest *)request { - return ([OHHTTPStubs.sharedInstance responseForRequest:request onlyCheck:YES] != nil); + return ([OHHTTPStubs.sharedInstance firstStubPassingTestForRequest:request] != nil); } - (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)response client:(id)client @@ -266,7 +307,14 @@ - (void)startLoading NSURLRequest* request = self.request; id client = self.client; - OHHTTPStubsResponse* responseStub = [OHHTTPStubs.sharedInstance responseForRequest:request onlyCheck:NO]; + OHHTTPStubsDescriptor* stub = [OHHTTPStubs.sharedInstance firstStubPassingTestForRequest:request]; + NSAssert(stub, @"At the time startLoading is called, canInitRequest should have assured that stub is != nil beforehand"); + OHHTTPStubsResponse* responseStub = stub.responseBlock(request); + + if (OHHTTPStubs.sharedInstance.onStubActivationBlock) + { + OHHTTPStubs.sharedInstance.onStubActivationBlock(request, stub); + } if (responseStub.error == nil) { @@ -456,7 +504,7 @@ - (void) streamDataForClient:(id)client // Delayed execution utility methods ///////////////////////////////////////////// -void execute_after(NSTimeInterval delayInSeconds, dispatch_block_t block) +static void execute_after(NSTimeInterval delayInSeconds, dispatch_block_t block) { dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); diff --git a/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h b/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h index b4c5beeb..3757d763 100644 --- a/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h +++ b/OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h @@ -56,7 +56,7 @@ */ +(instancetype)responseWithHTTPMessageData:(NSData*)responseData responseTime:(NSTimeInterval)responseTime -__attribute__((deprecated("Use responseWithHTTPMessageData: and requestTime:responseTime: instead"))); +__deprecated_msg("Use responseWithHTTPMessageData: and requestTime:responseTime: instead"); /*! @warning This method is deprecated @@ -74,7 +74,7 @@ __attribute__((deprecated("Use responseWithHTTPMessageData: and requestTime:resp +(instancetype)responseNamed:(NSString*)responseName fromBundle:(NSBundle*)bundle responseTime:(NSTimeInterval)responseTime -__attribute__((deprecated("Use responseNamed:inBundle: and requestTime:responseTime: instead"))); +__deprecated_msg("Use responseNamed:inBundle: and requestTime:responseTime: instead"); @end diff --git a/OHHTTPStubs/OHHTTPStubsResponse+JSON.h b/OHHTTPStubs/OHHTTPStubsResponse+JSON.h index bf2f9f6b..8ba677fa 100644 --- a/OHHTTPStubs/OHHTTPStubsResponse+JSON.h +++ b/OHHTTPStubs/OHHTTPStubsResponse+JSON.h @@ -54,6 +54,6 @@ statusCode:(int)statusCode responseTime:(NSTimeInterval)responseTime headers:(NSDictionary*)httpHeaders -__attribute__((deprecated("Use responseWithJSONObject:statusCode:headers: and requestTime:responseTime: instead"))); +__deprecated_msg("Use responseWithJSONObject:statusCode:headers: and requestTime:responseTime: instead"); @end diff --git a/OHHTTPStubs/OHHTTPStubsResponse.h b/OHHTTPStubs/OHHTTPStubsResponse.h index 248f5c20..b5c42323 100644 --- a/OHHTTPStubs/OHHTTPStubsResponse.h +++ b/OHHTTPStubs/OHHTTPStubsResponse.h @@ -52,7 +52,7 @@ OHHTTPStubsDownloadSpeedWifi; @property(nonatomic, strong) NSDictionary* httpHeaders; @property(nonatomic, assign) int statusCode; -@property(nonatomic, strong) NSData* responseData __attribute__((deprecated("Will be removed in next version. Use inputSteam property instead."))); +@property(nonatomic, strong) NSData* responseData __deprecated_msg("Will be removed in next version. Use inputSteam property instead."); @property(nonatomic, strong) NSInputStream* inputStream; @property(nonatomic, assign) unsigned long long dataSize; @property(nonatomic, assign) NSTimeInterval requestTime; //!< Defaults to 0.0 @@ -249,7 +249,7 @@ OHHTTPStubsDownloadSpeedWifi; statusCode:(int)statusCode responseTime:(NSTimeInterval)responseTime headers:(NSDictionary*)httpHeaders -__attribute__((deprecated("Use responseWithData:statusCode:headers: + requestTime:responseTime: instead"))); +__deprecated_msg("Use responseWithData:statusCode:headers: + requestTime:responseTime: instead"); /*! @warning This method is deprecated @@ -270,7 +270,7 @@ __attribute__((deprecated("Use responseWithData:statusCode:headers: + requestTim statusCode:(int)statusCode responseTime:(NSTimeInterval)responseTime headers:(NSDictionary*)httpHeaders -__attribute__((deprecated("Use responseWithFileAtPath:statusCode:headers: + requestTime:responseTime: instead"))); +__deprecated_msg("Use responseWithFileAtPath:statusCode:headers: + requestTime:responseTime: instead"); /*! @warning This method is deprecated @@ -289,7 +289,7 @@ __attribute__((deprecated("Use responseWithFileAtPath:statusCode:headers: + requ +(instancetype)responseWithFile:(NSString*)fileName contentType:(NSString*)contentType responseTime:(NSTimeInterval)responseTime -__attribute__((deprecated("Use responseWithFileAtPath:statusCode:headers: + requestTime:responseTime: instead"))); +__deprecated_msg("Use responseWithFileAtPath:statusCode:headers: + requestTime:responseTime: instead"); /*! @warning This method is deprecated @@ -310,7 +310,7 @@ __attribute__((deprecated("Use responseWithFileAtPath:statusCode:headers: + requ statusCode:(int)statusCode responseTime:(NSTimeInterval)responseTime headers:(NSDictionary*)httpHeaders -__attribute__((deprecated("Use initWithData:statusCode:headers: + requestTime:responseTime: instead"))); +__deprecated_msg("Use initWithData:statusCode:headers: + requestTime:responseTime: instead"); @end diff --git a/OHHTTPStubsDemo/MainViewController.m b/OHHTTPStubsDemo/MainViewController.m index 9e690c09..7854fb5f 100644 --- a/OHHTTPStubsDemo/MainViewController.m +++ b/OHHTTPStubsDemo/MainViewController.m @@ -28,6 +28,9 @@ - (void)viewDidLoad [self installTextStub:self.installTextStubSwitch]; [self installImageStub:self.installImageStubSwitch]; + [OHHTTPStubs onStubActivation:^(NSURLRequest *request, id stub) { + NSLog(@"[OHHTTPStubs] Request to %@ has been stubbed with %@", request.URL, stub.name); + }]; } - (void)viewDidUnload { @@ -46,6 +49,8 @@ - (IBAction)toggleStubs:(UISwitch *)sender self.delaySwitch.enabled = sender.on; self.installTextStubSwitch.enabled = sender.on; self.installImageStubSwitch.enabled = sender.on; + + NSLog(@"Installed (%@) stubs: %@", (sender.on?@"and enabled":@"but disabled"), OHHTTPStubs.allStubs); } @@ -79,7 +84,7 @@ - (IBAction)downloadText:(UIButton*)sender - (IBAction)installTextStub:(UISwitch *)sender { - static OHHTTPStubsID textStub = nil; // Note: no need to retain this value, it is retained by the OHHTTPStubs itself already :) + static id textStub = nil; // Note: no need to retain this value, it is retained by the OHHTTPStubs itself already if (sender.on) { // Install @@ -94,6 +99,7 @@ - (IBAction)installTextStub:(UISwitch *)sender requestTime:self.delaySwitch.on ? 2.f: 0.f responseTime:OHHTTPStubsDownloadSpeedWifi]; }]; + textStub.name = @"Text stub"; } else { @@ -125,7 +131,7 @@ - (IBAction)downloadImage:(UIButton*)sender - (IBAction)installImageStub:(UISwitch *)sender { - static OHHTTPStubsID imageStub = nil; // Note: no need to retain this value, it is retained by the OHHTTPStubs itself already :) + static id imageStub = nil; // Note: no need to retain this value, it is retained by the OHHTTPStubs itself already :) if (sender.on) { // Install @@ -140,6 +146,7 @@ - (IBAction)installImageStub:(UISwitch *)sender requestTime:self.delaySwitch.on ? 2.f: 0.f responseTime:OHHTTPStubsDownloadSpeedWifi]; }]; + imageStub.name = @"Image stub"; } else { diff --git a/README.md b/README.md index 5bb6e999..fa5353ed 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ It works with `NSURLConnection`, `AFNetworking`, or any networking framework you * [Advanced Usage](#advanced-usage) * [Use macros to build your fixtures path](#use-macros-to-build-your-fixtures-path) * [Using download speed instead of responseTime](#using-download-speed-instead-of-responsetime) - * [Stack multiple stubs and remove stubs](#stack-multiple-stubs-and-remove-stubs) + * [Stack multiple stubs and remove installed stubs](#stack-multiple-stubs-and-remove-installed-stubs) + * [Name your stubs and log their activation](#name-your-stubs-and-log-their-activation) * [Installing in your projects](#installing-in-your-projects) * [About OHHTTPStubs Unit Tests](#about-ohhttpstubs-unit-tests) * [Change Log](#change-log) @@ -138,26 +139,49 @@ Example: -### Stack multiple stubs and remove stubs +### Stack multiple stubs and remove installed stubs -You can call `stubRequestsPassingTest:withStubResponse:` multiple times. It will just add the stubs in an internal list of stubs. +* You can call `stubRequestsPassingTest:withStubResponse:` multiple times. It will just add the stubs in an internal list of stubs. _This may be useful to install different stubs in various places in your code, or to separate different stubbing conditions more easily. See the `OHHTTPStubsDemo` project for a typical example._ When a network request is performed by the system, the **stubs are called in the reverse order that they have been added**, the last added stub having priority over the first added ones. The first stub that returns YES for the first parameter of `stubRequestsPassingTest:withStubResponse:` is then used to reply to the request. -You can remove any given stub with the `removeStub:` method. This method takes as a parameter the object returned by `stubRequestsPassingTest:withStubResponse:` _(Note: this returned object is already retained by `OHHTTPStubs` while the stub is installed, so there is no need to keep a `__strong` reference to it)_. -You can also remove and all stubs at once with the `removeAllStubs` method, or only the latest added stub with the `removeLastStub` method. +* You can remove any given stub with the `removeStub:` method. This method takes as a parameter the `id` object returned by `stubRequestsPassingTest:withStubResponse:` _(Note: this returned object is already retained by `OHHTTPStubs` while the stub is installed, so there is no need to keep a `__strong` reference to it)_. +* You can remove the latest added stub with the `removeLastStub` method. +* You can also remove all stubs at once with the `removeAllStubs` method. - -When using `OHHTTPStubs` to build your Unit Tests, don't forget to remove all installed stubs at the end of each of your test case, to avoid stubs installed in one test case to be still installed for the next test case. +This last one is useful when using `OHHTTPStubs` in your Unit Tests, to remove all installed stubs at the end of each of your test case to avoid stubs installed in one test case to be still installed for the next test case. - (void)tearDown { [OHHTTPStubs removeAllStubs]; } +### Name your stubs and log their activation + +You can add a name (at your convenience) to your stubs. The only purpose of this is for debug & display in your console or anywhere else. + + id stub = [OHHTTPStubs stubRequestsPassingTest:... withStubResponse:...]; + stub.name = @"Stub for text files"; + +You can even imagine appling the `.name = ...` affectation directly if you don't intend to use the `id` in a variable: + + [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { + ... + } withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) { + ... + }].name = @"Stub for text files"; + +You can then list all the installed stubs using `[OHHTTPStubs allStubs]`, which return an array of `id` objects so you can display their `name` on the console. This is useful to check that you didn't forget to remove some previous stubs that are still installed for example. + +You can also setup a block to execute each time a request has been stubbed, using `onStubActivation:` method, typically to log the stub being used for each request: + + [OHHTTPStubs onStubActivation:^(NSURLRequest *request, id stub) { + NSLog(@"%@ stubbed %@", request.URL, stub.name); + }]; + ---- ## Installing in your projects @@ -187,4 +211,3 @@ This project and library has been created by Olivier Halligon (@AliSoftware) and It has been inspired by [this article from InfiniteLoop.dk](http://www.infinite-loop.dk/blog/2011/09/using-nsurlprotocol-for-injecting-test-data/). I would also like to thank to @kcharwood for its contribution, and everyone who contributed to this project on GitHub. -