A class to stub network requests easily: test your apps with fake network data (stubbed from file) and custom response time
- Basic Usage
- The
OHHTTPStubsResponse
object - Advanced Usage
- Return a response depending on the request
- Using download speed instead of responseTime
- Return quickly when
onlyCheck=YES
- Stack multiple requestHandlers
- Complete Examples
- Using in your projects
- Change Log
- License and Credits
This is aimed to be very simple to use. It uses block to intercept outgoing requests and allow you to return data from a file instead.
This is the most simple way to use it:
[OHHTTPStubs addRequestHandler:^OHHTTPStubsResponse*(NSURLRequest *request, BOOL onlyCheck)
{
return [OHHTTPStubsResponse responseWithFile:@"response.json" contentType:@"text/json" responseTime:2.0];
}];
This will return the NSData
corresponding to the content of the "response.json"
file (that must be in your bundle)
with a "Content-Type"
header of "text/json"
in the HTTP response, after 2 seconds.
Each time a network request is done by your application
(whatever the framework used, NSURLConnection
, AFNetworking, or anything else)
this requestHandler block will be called, allowing you to return an OHHTTPStubsResponse
object
describing the response to return.
- If you return a non-nil
OHHTTPStubsResponse
, it will automatically build aNSURLResponse
with your stubbed data, and behave exactly like if you received this response data from the network (this is transparent for the rest of the code). - If your return
nil
, the normal request will be sent (no stubbing).
The OHHTTPStubsResponse
class exposes multiple initializers:
+(id)responseWithData:(NSData*)data
statusCode:(int)statusCode
responseTime:(NSTimeInterval)responseTime
headers:(NSDictionary*)httpHeaders;
+(id)responseWithFile:(NSString*)fileName
statusCode:(int)statusCode
responseTime:(NSTimeInterval)responseTime
headers:(NSDictionary*)httpHeaders;
Useful short-form initializer to load data from a file in your bundle, using the specified "Content-Type" header
+(id)responseWithFile:(NSString*)fileName
contentType:(NSString*)contentType
responseTime:(NSTimeInterval)responseTime;
+(id)responseWithError:(NSError*)error;
(e.g. you could use an error like [NSError errorWithDomain:NSURLErrorDomain code:404 userInfo:nil]
)
Of course, and that's the main reason this is implemented with blocks, you can do whatever you need in the block implementation. This includes checking the request URL to see if you want to return a stub or not, and pick the right file according to the requested URL.
Example:
[OHHTTPStubs addRequestHandler:^OHHTTPStubsResponse*(NSURLRequest *request, BOOL onlyCheck)
{
NSString* basename = request.URL.absoluteString.lastPathComponent;
if ([basename.pathExtension isEqualToString:@"json"]) {
return [OHHTTPStubsResponse responseWithFile:basename contentType:@"text/json" responseTime:2.0];
} else {
return nil; // Don't stub
}
}];
When building the OHHTTPStubsResponse
object, you can specify a response time (in seconds) so
that the sending of the fake response will be postponed (using GCD's dispatch_after function
).
This allows you to simulate a slow network for example.
If you specify a negative value for the responseTime parameter, instead of being interpreted as a time in seconds, it will be interpreted as a download speed in KBytes/s. In that case, the response time will be computed using the size of the response's data to simulate the indicated download speed.
The OHHTTPStubsResponse
header defines some constants for standard download speeds:
OHHTTPStubsDownloadSpeedGPRS
: 56 kbps (7 KB/s)OHHTTPStubsDownloadSpeedEDGE
: 128 kbps (16 KB/s)OHHTTPStubsDownloadSpeed3G
: 3200 kbps (400 KB/s)OHHTTPStubsDownloadSpeed3GPlus
: 7200 kbps (900 KB/s)OHHTTPStubsDownloadSpeedWifi
: 12000 kbps (1500 KB/s)
If the onlyCheck
parameter of the requestHandler block is YES
, then it means that the handler is called
only to check if you will be able to return a stubbed response or if it has to do the standard request.
In this scenario, the response will not actually be used but will only be compared to nil
to check if it has to be stubbed later.
The handler will be called later again (with onlyCheck=NO
) to fetch the actual OHHTTPStubsResponse
object.
So in such cases (onlyCheck==YES
), you can simply return nil
if you don't want to provide a stubbed response,
and any non-nil value to indicate that you will provide a stubbed response later.
This may be useful if you intend to do some not-so-fast work to build your real OHHTTPStubsResponse
(like reading some large file for example): in that case you can quickly return a dummy value when onlyCheck==YES
without the burden of building the actual OHHTTPStubsResponse
object.
You will obviously return the real OHHTTPStubsResponse
in the later call when onlyCheck==NO
.
There is a macro OHHTTPStubsResponseUseStub
provided in the header that you can use as a dummy return value
for that purpose (it actually evaluates to (OHHTTPStubsReponse*)1
)
You can call +addRequestHandler:
multiple times.
It will just add the response handlers in an internal list of handler.
When a network request is performed by the system, the response handlers are called in the reverse
order that they have been added, the last added handler having priority over the first added ones.
The first non-nil OHHTTPStubsResponse
returned is used to reply to the request.
This may be useful to install different stubs in different classes (say different UIViewControllers) and various places in your application.
You can remove the latest added handler with the removeLastRequestHandler
method.
You can also remove any given handler with the removeRequestHandler:
method. This method takes as a parameter the object returned by addRequestHandler:
. Note that this returned object is already retained by OHHTTPStubs
, so you may keep it in a __weak
variable.
Here is another example code below that uses the various techniques explained above.
For a complete Xcode projet, see the OHHTTPStubsDemo.xcworkspace
project in the repository.
NSArray* stubs = [NSArray arrayWithObjects:@"file1", @"file2", nil];
[OHHTTPStubs addRequestHandler:^OHHTTPStubsResponse*(NSURLRequest *request, BOOL onlyCheck)
{
NSString* basename = [request.URL.absoluteString lastPathComponent];
if (onlyCheck) {
return ([stubs containsObject:basename] ? OHHTTPStubsResponseUseStub : nil);
}
NSString* file = [basename stringByAppendingPathExtension:@"json"];
return [OHHTTPStubsResponse responseWithFile:file contentType:@"text/json"
responseTime:OHHTTPStubsDownloadSpeedEDGE];
}];
...
// Then this call (sending a request using the AFNetworking framework) will actually
// receive a fake response issued from the file "file1.json"
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.example.com/file1"]];
AFJSONRequestOperation* req =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
...
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)
{
...
}];
[req start];
The OHHTTPStubs
project is provided as a Xcode project that generates a static library, to easily integrate it with your project.
- Add the
OHHTTPStubs.xcodeproj
project to your application workspace, next to your application project - Link
libOHHTTPStubs.a
with your application project:
- Select your application project in the Project Navigator, then select your target in which you want to use
OHHTTPStubs
(for example your Tests target if you will only useOHHTTPStubs
in your Unit Tests) - Go to the "Build Phase" tab and open the "Link Binary With Libraries" phase
- Use the "+" button to add the
libOHHTTPStubs.a
library to the libraries linked with your project
- When you need to use
OHHTTPStubs
classes, import the headers using square brackets:#import <OHHTTPStubs/OHHTTPStubs.h>
Note: due to a bug in Xcode4, you will have to ensure that the libOHHTTPStubs.a
file reference added in your project
has its path referenced as "Relative to Build Products" as it should.
If it is not the case, please read the detailed instructions here.
Important Note:
OHHTTPStubs
is designed to be used in test/debug code only. Don't link with it in production code when you compile your final application for the AppStore.
Its code use a private API to build an
NSHTTPURLResponse
, which is not authorized by Apple in applications published on the AppStore. So you will probably only link it with your Unit Tests target, or inside some#if DEBUG
/#endif
portions of your code.
The changelog is available here in the dedicated wiki page.
This project is brought to you by Olivier Halligon and is under MIT License
It has been inspired by this article from InfiniteLoop.dk (See also his GitHub repository)