-
Notifications
You must be signed in to change notification settings - Fork 601
Testing for the request body in your stubs
As seen in issue #52, unfortunately when you send POST
requests (with a body) using NSURLSession
, by the time the request arrives to OHHTTPStubs
, the HTTPBody
of the NSURLRequest
can't be accessed anymore (probably already transformed internally to an HTTPBodyStream
?). This is a known Apple bug.
Therefore, you cannot directly test the request.HTTPBody
in your [OHHTTPStubs stubRequestsPassingTest:withStubResponse:]
as the HTTPBody
property will return nil
at that time.
Since version 5.1.0 and thanks to the PR #166 submitted by @felixLam and @shagedorn, you can now check the property OHHTTPStubs_HTTPBody
instead when you need to test for the HTTPBody
.
This property is provided as an extension/category on the NSURLRequest
class which contains a copy of the HTTPBody
but which, contrary to the HTTPBody
property, isn't reset to nil
by iOS by the time you test the NSURLRequest
in your stubs. This way you can now check the content of that NSData
and return different stubs depending on them too.
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
// Only stub POST requests with a body equal to "user=foo&password=bar"
NSData* body = request.OHHTTPStubs_HTTPBody;
NSString* bodyString = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
return [request.HTTPMethod isEqualToString:@"POST"]
&& [bodyString isEqualToString:@"user=foo&password=bar"];
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
return [OHHTTPStubsResponse responseWithData:validLoginResponseData statusCode:200 headers:headers];
}].name = @"login";
Another nice trick to know is the existence of [NSURLProtocol setProperty:forKey:inRequest:]
, which allows you to associate arbitrary key/value pairs to your NSURLRequests
, that you can later query using [NSURLProtocol propertyForKey:inRequest:]
.
Thus you can easily use this method to store any meta data you want to associate with your request, like the parameters dictionary used to build the query part of your GET
URLs, or the RPC
method that your request intends to call, etc. This will then allow you to use those meta-data to conditionally stub your requests with easier conditional checks (like retrieve the RPC method you previously associated with that NSURLRequest
in your OHHTTPStubs
test block and check on it to decide which stub to return, for example).
If you are using AFNetworking
2.0+ to build your request, you can provide a custom AFHTTPRequestSerializer
class to associate some properties to your requests when building them.
Here is an example (in ObjC, but you could easily translate it to Swift) on how to do that to automatically associate the parameters and body to each request build using the RequestSerializer.
@interface AnnotatedRequestSerializer : AFHTTPRequestSerializer @end
@implementation AnnotatedRequestSerializer
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
error:(NSError * __autoreleasing *)error
{
NSMutableURLRequest* req = [super requestWithMethod:method URLString:URLString parameters:parameters error:error];
[NSURLProtocol setProperty:parameters forKey:@"parameters" inRequest:req];
[NSURLProtocol setProperty:req.HTTPBody forKey:@"HTTPBody" inRequest:req];
return req;
}
@end
sessionMgr = [[AFHTTPSessionManager alloc] initWithBaseURL:… sessionConfiguration:…];
sessionMgr.requestSerializer = [AnnotatedRequestSerializer serializer];
[sessionMgr POST:@"/login"
parameters:@{ @"login":@"foo", @"password":@"bar" }
success:…
failure:…
];
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
NSDictionary* requestParams = [NSURLProtocol propertyForKey:@"parameters" inRequest:request];
// Only stub POST requests to "/login" with "user" = "foo" & "password" = "bar"
return [request.HTTPMethod isEqualToString:@"POST"]
&& [request.URL.path isEqualToString:@"/login"]
&& [requestParams[@"user"] isEqualToString:@"foo"]
&& [requestParams[@"password"] isEqualToString:@"bar"];
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
return [OHHTTPStubsResponse responseWithData:validLoginResponseData statusCode:200 headers:headers];
}].name = @"login";