Comments (9)
+1
from nocilla.
I'm having the same problem, but I think the problem is not with Nocilla. It seems like NSURLSession and NSURLProtocol doesn't play well together under a testing environment.
In the example below the method + (BOOL)canInitWithRequest: is never called.
#import <XCTest/XCTest.h>
#define TestNeedsToWaitForBlock() __block BOOL blockFinished = NO
#define BlockFinished() blockFinished = YES
#define WaitForBlock() while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !blockFinished)
@interface NSURLProtocolImpl : NSURLProtocol
@end
@implementation NSURLProtocolImpl
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
NSLog(@"NSURLProtocolImpl canInitWithRequest: %@", request);
return NO;
}
@end
@interface NSUrlProtocolTests : XCTestCase
@end
@implementation NSUrlProtocolTests
- (void)setUp
{
[super setUp];
[NSURLProtocol registerClass:[NSURLProtocolImpl class]];
}
- (void)tearDown
{
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample
{
TestNeedsToWaitForBlock();
NSURL *url = [NSURL URLWithString:@"http://www.example.com"];
NSURLSession *urlsession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDataTask *datatask = [urlsession dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error) {
NSLog(@"error: %@", error);
}
else {
NSLog(@"Success");
}
BlockFinished();
}];
[datatask resume];
WaitForBlock();
}
@end
This was tested with XCode 5.0 (5A1412) and iOS 7 simulator.
from nocilla.
I believe the reason this is not working out of the box is because you have to register the LSHTTPStubURLProtocol via the NSUSerSessionConfiguration's protocolClasses array instead of using the registerClass method (see https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionConfiguration_class/Reference/Reference.html#//apple_ref/doc/uid/TP40013440-CH1-SW24).
So something like this in your test setup
...
NSURLSessionConfiguration configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.protocolClasses=@[[LSHTTPStubURLProtocol class]];
...
from nocilla.
@gdunkle is correct that the LSHTTPStubURLProtocol
is not properly getting registered when using NSURLSession
. However, there does not appear to be a way to globally register it for all instances of NSURLSession
. This is one of the advantages of NSURLSession
is that each instance can have its own set of configuration settings, cookies stores, etc.
This means getting this to work in testing is more difficult. You cannot modify the defaults in the way above because defaultsessionConfiguration
returns a copy so modifying the copy does not change the configuration for all users of the class. Instead, you will need to allow the configuration to be set or injected into the class you are testing.
Unfortunately, if you are using Nocilla for automated UI testing, you'll need to figure out how you want to do that for only when running tests (I'm using a preprocessing statements, which I'm not happy with).
from nocilla.
Yeah it's non trivial but definitely doable (at least with AFNetworking). I have it working for my tests by first extending AFHTTPSessionManager
@interface HttpSessionManager : AFHTTPSessionManager
@end
@implementation HttpSessionManager
-(instancetype)init{
//this retrieval of base url is specific to my implementation the main thing is you call the super constructor that you're wrapping in the category below
NSString *baseUrl = [[Properties instance]config][@"baseUrl"];
self = [super initWithBaseURL:[NSURL URLWithString:baseUrl]];
if(!self){
return nil;
}
return self;
}
@end
Then in my test I use a category to add a wrapper around the init method of HttpSessionManager and swizzle the initWithBaseURL and wrap_initWithBaseURL
@interface HttpSessionManager (AddTestProtocols)
@end
@implementation HttpSessionManager (AddTestProtocols)
- (instancetype)wrap_initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration{
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
//set the protocol class here!
configuration.protocolClasses=@[[LSHTTPStubURLProtocol class]];
return [self wrap_initWithBaseURL:url sessionConfiguration:configuration];
}
//swizzle the initWithBaseURL and wrap_initWithBaseURL
+ (void)load
{
Method original, swizzled;
SEL originalSelector=@selector(initWithBaseURL:sessionConfiguration:);
SEL swizzledSelector=@selector(wrap_initWithBaseURL:sessionConfiguration:);
original = class_getInstanceMethod(self, originalSelector);
swizzled = class_getInstanceMethod(self, swizzledSelector);
method_exchangeImplementations(original, swizzled);
}
@end
Of course my example is using AFNetworking's extension of the NSUrlSession stuff but I imagine the same principals could be applied.
This method has been working quite well for me.
from nocilla.
My solution ended up being pretty simple. I already have a class which manages my AFHTTPSessionManager
, so I simply added a method to hijack it.
Network.m
+ (AFHTTPSessionManager *)api
{
return [Network sharedInstance].apiSession;
}
// Used with testing
- (void)hijackSessionWithProtocolClasses:(NSArray *)protocolClasses
{
NSURLSessionConfiguration *hijackedConfig = self.apiSession.session.configuration;
hijackedConfig.protocolClasses = protocolClasses;
[self.apiSession invalidateSessionCancelingTasks:YES];
self.apiSession = [[AFHTTPSessionManager alloc] initWithBaseURL:self.apiURL sessionConfiguration:hijackedConfig];
}
Then in my tests I just make sure to hijack it:
MyAPIControllerTests.m
- (void)setUp
{
[[Network sharedInstance] hijackSessionWithProtocolClasses:@[[LSHTTPStubURLProtocol class]]];
}
And then everything worked just fine. I had some trouble referencing LSHTTPStubURLProtocol
, since the podspec
didn't expose it. But once I changed the spec locally everything was great. I've submitted #54 to update the podspec to let others do something similar.
from nocilla.
@timshadel's fix worked for me! Would be awesome to get this included so we could use AFHTTPSessionManager out of the box!
from nocilla.
@timshadel looks like your fix was turned down in order to have issue #60 implemented. I can't seem to figure out how to get the solution in #60 to catch my NSURLSession
-driven requests. Shouldn't Nocilla raise an NocillaUnexpectedRequest
exception if any request calls out that's not stubbed? Because it doesn't seem to be working for me.
MyClass
below is a subclass of AFNetworking's AFHTTPSessionManager
and it makes a POST
call inside the implementation. No big surprises there.
describe(@"MyClass", ^{
beforeAll(^{
[[LSNocilla sharedInstance] start];
});
afterEach(^{
[[LSNocilla sharedInstance] clearStubs];
});
afterAll(^{
[[LSNocilla sharedInstance] stop];
});
it(@"does the thing", ^AsyncBlock{
[MyClass makeThatAPICallWithCompletion:^(NSURLSessionDataTask *task, id data, NSError *error) {
NSInteger statusCode = [(NSHTTPURLResponse *)task.response statusCode];
expect(data).willNot.beNil();
expect(statusCode).will.equal(200);
done();
}];
});
});
It lets the request go through just fine; no exception is raised. Do I need to register LSNSURLSessionHook
as a hook with Nocilla, similar to how LSASIHTTPRequestHook
is registered in the readme?
[[LSNocilla sharedInstance] registerHook:[[LSASIHTTPRequestHook alloc] init]];
LSNSURLSessionHook.h
file isn't even exposed through the pod, it seems.
Edit: stranger still, when Travis CI Pro checks out and builds my project, it raises the exception… but not on my local machine, not when running the exact same command that Travis runs (which is an xctool
command).
from nocilla.
@kreeger can you open a new issue with a sample project, please?
I'm closing this issue since it should work as of #60, release in 0.8.0. Please open new issues with any questions or well... issues.
Thanks.
from nocilla.
Related Issues (20)
- Sporadic results (XCTest) when running simultaneous tests HOT 5
- Not able to stub cookies for normal (non-directed requests) HOT 1
- Body matcher fails to match arbitrary NSData
- Support for RestKit HOT 1
- Add 0.10.0 to CocoaPods.org HOT 1
- Synchronous Request Support
- Wait for async request to complete before stop() HOT 1
- Crash in LSHTTPStubURLProtocol - EXC_BAD_ACCESS - Specific way to stub redirects? HOT 1
- Ability to Delay a Response HOT 1
- Redirect Implementation is Inconsistent With OS Behavior
- Carthage Binaries HOT 1
- ASIHTTPRequest synchronous request with stub never ends HOT 1
- LSNocilla.sharedInstance().stop() Not working HOT 5
- Project no longer maintained? HOT 3
- Nocilla never returns the stub HOT 2
- App store rejection due to private api references HOT 3
- Use this snippet to stub the request HOT 1
- Push v0.11.0 podspec to Cocoapods HOT 2
- Swift 3 Support HOT 2
- How do I Nocilla in Swift 3? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nocilla.