Stub your network requests easily! Test your apps with fake network data and custom response time, response code and headers!

Overview

OHHTTPStubs

Platform Language: Swift-2.x/3.x/4.x/5.x Build Status

Version Carthage Supported Swift Package Manager Supported

OHHTTPStubs is a library designed to stub your network requests very easily. It can help you:

  • test your apps with fake network data (stubbed from file) and simulate slow networks, to check your application behavior in bad network conditions
  • write unit tests that use fake network data from your fixtures.

It works with NSURLConnection, NSURLSession, AFNetworking, Alamofire or any networking framework that use Cocoa's URL Loading System.

Donate


Documentation & Usage Examples

OHHTTPStubs headers are fully documented using Appledoc-like / Headerdoc-like comments in the header files. You can also read the online documentation here.

Basic example

In Objective-C
[HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
  return [request.URL.host isEqualToString:@"mywebservice.com"];
} withStubResponse:^HTTPStubsResponse*(NSURLRequest *request) {
  // Stub it with our "wsresponse.json" stub file (which is in same bundle as self)
  NSString* fixture = OHPathForFile(@"wsresponse.json", self.class);
  return [HTTPStubsResponse responseWithFileAtPath:fixture
            statusCode:200 headers:@{@"Content-Type":@"application/json"}];
}];
In Swift

This example is using the Swift helpers found in OHHTTPStubsSwift.swift provided by the OHHTTPStubs/Swift subspec or OHHTTPStubs package.

stub(condition: isHost("mywebservice.com")) { _ in
  // Stub it with our "wsresponse.json" stub file (which is in same bundle as self)
  let stubPath = OHPathForFile("wsresponse.json", type(of: self))
  return fixture(filePath: stubPath!, headers: ["Content-Type":"application/json"])
}

Note: if you're using OHHTTPStubs's Swiftier API (OHHTTPStubsSwift.swift and the Swift subspec or OHTTPStubsSwift package), you can also compose the matcher functions like this: stub(isScheme("http") && isHost("myhost")) { … }

More examples & Help Topics

Recording requests to replay them later

Instead of writing the content of the stubs you want to use manually, you can use tools like SWHttpTrafficRecorder to record network requests into files. This way you can later use those files as stub responses.
This tool can record all three formats that are supported by OHHTTPStubs (the HTTPMessage format, the simple response boby/content file, and the Mocktail format).

(There are also other ways to perform a similar task, including using curl -is <url> >foo.response to generate files compatible with the HTTPMessage format, or using other network recording libraries similar to SWHttpTrafficRecorder).

Compatibility

  • OHHTTPStubs is compatible with iOS5+, OS X 10.7+, tvOS.
  • OHHTTPStubs also works with NSURLSession as well as any network library wrapping them.
  • OHHTTPStubs is fully compatible with Swift 3.x, 4.x and Swift 5.x.

Nullability annotations have also been added to the ObjC API to allow a cleaner API when used from Swift even if you don't use the dedicated Swift API wrapper provided by OHHTTPStubsSwift.swift.

Updating to Version 9.0+
  • All classes dropped the OH prefix (OHHHTTPStubs -> HTTPStubs, OHHTTPStubsResponse -> HTTPStubsResponse, etc).
  • The OHPathHelpers class was renamed HTTPStubsPathHelpers.
  • No method and module names were changed.

Installing in your projects

CocoaPods

Using CocoaPods is the recommended way.

  • If you intend to use OHHTTPStubs from Objective-C only, add pod 'OHHTTPStubs' to your Podfile.
  • If you intend to use OHHTTPStubs from Swift, add pod 'OHHTTPStubs/Swift' to your Podfile instead.
pod 'OHHTTPStubs/Swift' # includes the Default subspec, with support for NSURLSession & JSON, and the Swiftier API wrappers

All available subspecs

OHHTTPStubs is split into subspecs so that when using Cocoapods, you can get only what you need, no more, no less.

  • The default subspec includes NSURLSession, JSON, and OHPathHelpers
  • The Swift subspec adds the Swiftier API to that default subspec
  • HTTPMessage and Mocktail are opt-in subspecs: list them explicitly if you need them
  • OHPathHelpers doesn't depend on Core and can be used independently of OHHTTPStubs altogether
List of all the subspecs & their dependencies

Here's a list of which subspecs are included for each of the different lines you could use in your Podfile:

Subspec Core NSURLSession JSON Swift OHPathHelpers HTTPMessage Mocktail
pod 'OHHTTPStubs'
pod 'OHHTTPStubs/Default'
pod 'OHHTTPStubs/Swift'
pod 'OHHTTPStubs/Core'
pod 'OHHTTPStubs/NSURLSession'
pod 'OHHTTPStubs/JSON'
pod 'OHHTTPStubs/OHPathHelpers'
pod 'OHHTTPStubs/HTTPMessage'
pod 'OHHTTPStubs/Mocktail'

Swift Package Manager

OHHTTPStubs is compatible with Swift Package Manager, and provides 2 targets for consumption: OHHTTPStubs and OHHTTPStubsSwift.

  • OHHTTPStubs is equivalent to the OHHTTPStubs subspec.
  • OHHTTPStubsSwift is equivalent to the OHHTTPStubs/Swift subspec.

Note: We currently do not have support for the HTTPMessage or Mocktail subspecs in Swift Package Manager. If you are interested in these, please open an issue to explain your needs.

Carthage

OHHTTPStubs is also compatible with Carthage. Just add it to your Cartfile.

Note: The OHHTTPStubs.framework built with Carthage will include all features of OHHTTPStubs turned on (in other words, all subspecs of the pod), including NSURLSession and JSON support, OHPathHelpers, HTTPMessage and Mocktail support, and the Swiftier API.

Using the right Swift version for your project

OHHTTPStubs supports Swift 3.0 (Xcode 8+), Swift 3.1 (Xcode 8.3+), Swift 3.2 (Xcode 9.0+), Swift 4.0 (Xcode 9.0+), Swift 4.1 (Xcode 9.3+), Swift 4.2 (Xcode 10+), Swift 5.0 (Xcode 10.2), and Swift 5.1 (Xcode 11) however we are only testing Swift 4.x (using Xcode 9.1 and 10.1) and Swift 5.x (using Xcode 10.2 AND 11) in CI.

Here are some details about the correct setup you need depending on how you integrated OHHTTPStubs into your project.

CocoaPods: nothing to do

If you use CocoaPods version 1.1.0.beta.1 or later, then CocoaPods will compile OHHTTPStubs with the right Swift Version matching the one you use for your project automatically. You have nothing to do! 🎉

For more info, see CocoaPods/CocoaPods#5540 and CocoaPods/CocoaPods#5760.

Carthage: choose the right version

The project is set up with SWIFT_VERSION=5.0 on master.

This means that the framework on master will build using:

  • Swift 5.1 on Xcode 11
  • Swift 5.0 on Xcode 10.2
  • Swift 4.2 on Xcode 10.1
  • Swift 4.0 on Xcode 9.1

If you want Carthage to build the framework with Swift 3.x you can:

  • either use an older Xcode version
  • or use the previous version of OHHTTPStubs (6.2.0) — whose master branch uses 3.0
  • or fork the repo just to change the SWIFT_VERSION build setting to 3.0
  • or build the framework passing a SWIFT_VERSION to carthage via XCODE_XCCONFIG_FILE=<config file declaring SWIFT_VERSION> carthage build

Special Considerations

Using OHHTTPStubs in your unit tests

OHHTTPStubs is ideal to write unit tests that normally would perform network requests. But if you use it in your unit tests, don't forget to:

  • remove any stubs you installed after each test — to avoid those stubs to still be installed when executing the next Test Case — by calling [HTTPStubs removeAllStubs] in your tearDown method. see this wiki page for more info
  • be sure to wait until the request has received its response before doing your assertions and letting the test case finish (like for any asynchronous test). see this wiki page for more info

Automatic loading

OHHTTPStubs is automatically loaded and installed (at the time the library is loaded in memory), both for:

  • requests made using NSURLConnection or [NSURLSession sharedSession]thanks to this code
  • requests made using a NSURLSession that was created via [NSURLSession sessionWithConfiguration:…] and using either [NSURLSessionConfiguration defaultSessionConfiguration] or [NSURLSessionConfiguration ephemeralSessionConfiguration] configuration — thanks to method swizzling done here in the code.

If you need to disable (and re-enable) OHHTTPStubs — globally or per NSURLSession — you can use [HTTPStubs setEnabled:] / [HTTPStubs setEnabled:forSessionConfiguration:].

Known limitations

  • OHHTTPStubs can't work on background sessions (sessions created using [NSURLSessionConfiguration backgroundSessionConfiguration]) because background sessions don't allow the use of custom NSURLProtocols and are handled by the iOS Operating System itself.
  • OHHTTPStubs don't simulate data upload. The NSURLProtocolClient @protocol does not provide a way to signal the delegate that data has been sent (only that some has been loaded), so any data in the HTTPBody or HTTPBodyStream of an NSURLRequest, or data provided to -[NSURLSession uploadTaskWithRequest:fromData:]; will be ignored, and more importantly, the -URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: delegate method will never be called when you stub the request using OHHTTPStubs.
  • OHTTPStubs has a known issue with redirects that we believe is an Apple bug. It has been discussed here and here. The actual result of this bug is that redirects with a zero second delay may nondeterministically end up with a null response.

As far as I know, there's nothing we can do about those three limitations. Please let me know if you know a solution that would make that possible anyway.

Submitting to the App Store

OHHTTPStubs can be used on apps submitted on the App Store. It does not use any private API and nothing prevents you from shipping it.

But you generally only use stubs during the development phase and want to remove your stubs when submitting to the App Store. So be careful to only include OHHTTPStubs when needed (only in your test targets, or only inside #if DEBUG sections, or by using per-Build-Configuration pods) to avoid forgetting to remove it when the time comes that you release for the App Store and you want your requests to hit the real network!

License and Credits

This project and library has been created by Olivier Halligon (@aligatr on Twitter) and is under the MIT License.

It has been inspired by this article from InfiniteLoop.dk.

I would also like to thank:

  • Sébastien Duperron (@Liquidsoul) for helping me maintaining this library, triaging and responding to issues and PRs
  • Kevin Harwood (@kcharwood) for migrating the code to NSInputStream
  • Jinlian Wang (@JinlianWang) for adding Mocktail support
  • and everyone else who contributed to this project on GitHub somehow.

If you want to support the development of this library, feel free to Donate. Thanks to all contributors so far!

Comments
  • Stubbing two requests in a single test case

    Stubbing two requests in a single test case

    One issue I've been running into lately has been when I want to test the process of multiple requests in a single test case. An example of this would be testing successfully unregistering from a server. First I want to simulate successfully registering with a server stubbing the response with a 200 and some JSON, and once that is done I want to stub the response with another 200 response and different JSON and then send the unregister request.

    I have a helper function I call in each test so I can quickly stub a response with a single line of code:

    - (void)stubResponseWithStatusCode:(int)statusCode dictionary:(NSDictionary *)responseDictionary delay:(NSTimeInterval)delay {
        [OHHTTPStubs removeLastStub];
    
        [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
            return YES;
        } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
            return [[OHHTTPStubsResponse responseWithJSONObject:responseDictionary statusCode:statusCode headers:nil] responseTime:delay];
        }];
    }
    

    EDIT: I've updated my current async testing strategy to take advantage of the XCTestExpectation APIs after reading your docs, rather than implement my own method, and the problem still exists.

    When I stub a response without any delay in the beginning of the test, send the request, and inside the completion block when the request is successful stub the NEXT request with a new response without any delay, there are times where the second response is never received, so the tests fail when they hit the 2-4 second timeout. Is this something you've seen before, a known issue, or operator error? Thanks!

    Question 
    opened by mamaral 33
  • Body of request never makes it to stubRequestPassingTest:

    Body of request never makes it to stubRequestPassingTest:

    I use OHHTTPStubs to test if my AFHTTPRequest send the correct xml as body in a request. This works fine and all tests pass, checking the body that would be sent in the stubRequestPassingTest:

    Now I moved to using AFHTTPSessionManager, and the program still works fine, but the tests fail, telling me that the body to be sent is empty, instead of the expected xml.

    Something funny that happens: the request that gets prepared by my program has a different pointer (0xe1efbc0) than the request (0xe2c3310) that is checked in the stub. Any idea what is going on? Is it possible the requests gets copied, but the body didn't make it to the copy?

    Here is a log from my console:

    2014-02-06 14:09:36.278 xctest[69495:303] Posting request 0xe1efbc0 with body: 2014-02-06 14:09:36.278 xctest[69495:1903] Stubbing url /admin/_cmdstat.jsp 2014-02-06 14:09:36.278 xctest[69495:1903] checking body of request 0xe2c3310 2014-02-06 14:09:36.279 xctest[69495:1903] Would sent body: /Volumes/InternalHD/Projecten/ZoneDirectorViewer/ZoneDirectorViewer/Connection/ServerConnectionTests.m:551: error: -[ServerConnectionTests testGetSystemInfo] : ((requestedBody) equal to (expectedBody)) failed: ("") is not equal to ("")

    Solution available Apple Bug 
    opened by jpalten 32
  • Stub not being called

    Stub not being called

    I'm setting up a stub in an Specta spec that isn't getting called. Here's the code I'm using:

    it(@"should request splashes", ^{
        __block BOOL success = NO ;
    
        [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
            return [request.URL.host isEqualToString:@"zamba.cs.vt.edu"];
        }
                            withStubResponse: ^OHHTTPStubsResponse *(NSURLRequest *request) {
                                NSData *stubData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"findSplashesResponse" ofType:@"txt"]];
                                NSDictionary *standardHeaders = @{ @"Content-Type":@"text/html"};
                                return [OHHTTPStubsResponse responseWithData:stubData statusCode:200 headers:standardHeaders];
                            }].name = @"findSplashes.php";
        [OHHTTPStubs setEnabled:YES];
    
        [client POST:@"findSplashes.php"
          parameters:@{ @"hash": [client hashString],
                        @"lat":[NSString stringWithFormat:@"%f", vt.coordinate.latitude],
                        @"long":[NSString stringWithFormat:@"%f", vt.coordinate.longitude],
                        @"radius":@"1600" }
             success:^(NSURLSessionDataTask *task, id responseObject) {
                 NSString *response = [[NSString alloc] initWithData:(NSData *) responseObject encoding:NSUTF8StringEncoding];
                 success = [response isEqualToString:@"252\t5527.5387976613\t4\t4\t1387655919\t1387568319\t300\t40.739983\t-73.992951\n"] ? YES : NO;
             }
             failure:^(NSURLSessionDataTask *task, NSError *error) {
                 success = NO;
             }];
    
        expect(success).will.beTruthy();
    });
    

    client is a singleton instance of an AFHTTPSessionManager from AFNetworking 2.0. Strangely, this test and other similar tests were passing originally--I don't know what I've done to break them! When the POST request is made, I can check that OHHTTPStubs.sharedInstance is the same as when the stub was created. I've added the +[OHHTTPStubs setEnabled:] call per other issues here. The block passed as thestubRequestsPassingTest:` parameter is never executed--all requests hit the network. Any ideas? Thanks!

    Confirmed Bug Solution available 
    opened by brennon 31
  • Never calling the stub

    Never calling the stub

    Hi, I tried to implement stubs on xcode 5 with afnetworking 2.0 and it is not working. My current version of OHHTTPStubs pod is 3.0.0

      [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
        return YES;
      }
         withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
                            return [[OHHTTPStubsResponse alloc] init];
                          }];
    

    I am actually using an AFHTTPSessionManager singleton configured:

    + (instancetype)sharedInstance
    {
      static APTHttpClient *_sharedClient = nil;
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        _sharedClient = [[APTHttpClient alloc] initWithBaseURL:[NSURL URLWithString:APRProductionServer] sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
      });
    
      return _sharedClient;
    }
    

    This is the method I am actually calling after the stub:

    - (void)getContacts
    {
      [self GET:@"/contacts"
     parameters:nil
        success:^(NSURLSessionDataTask *task, id responseObject) {
          NSLog(@"%@",responseObject);
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
          NSLog(@"Error: %@", error.userInfo);
        }];
    }
    

    Is there something I am doing wrong?

    Confirmed Bug 
    opened by alvarezloaiciga 30
  • Adds support for HTTPBody during testing when using NSURLSession

    Adds support for HTTPBody during testing when using NSURLSession

    This addresses the issue described in https://github.com/AliSoftware/OHHTTPStubs/wiki/Testing-for-the-request-body-in-your-stubs and #52

    It also avoids unnecessary changes to the code under test as the setter and getter for HTTPBody can still be used without change in behavior (as far as one can tell).

    The new getter -[NSURLRequest OHHTTPStubs_HTTPBody] can be used in your [OHHTTPStubs stubRequestsPassingTest:withStubResponse:] to test the HTTPBody.

    One known issue is that if you set the HTTPBody and later reset it to nil (for whatever reason),OHHTTPStubs_HTTPBody will still return the last non-nil value.

    Thanks to @shagedorn for the help on method swizzling.

    opened by felixLam 26
  • Swift 3.0 support

    Swift 3.0 support

    Hi !

    I have picked up the work of @mxcl to make OHHTTPStubs support swift 3.0. The objective was to make the code works on every version of swift (2.2, 2.3, 3.0) to fix issue #189. To achieve this, I made some tradeoffs.

    Remove first parameter label in Swift 3.0

    To avoid declaring the methods multiple times to support both 2.3 and 3.0 syntax, some warnings are generated when using 2.x compilers. For example, so that we can still use isPath("myPath") in Swift 3.0, the declaration has been changed to func isPath(_ path: String) -> OHHTTPStubsTestBlock. This generates the following warning on 2.x compilers: Extraneous '_' in parameter: 'path' has no keyword argument name

    Multiple #if branching to instantiate either URLRequest or NSURLRequest in tests

    While we could do some tricks using extensions to support 3.0 methods and attributes in swift 2.x, this is not feasible for a whole struct/class like URLRequest/NSURLRequest. So, in the tests, every time we were instantiating a NSURLRequest object, the call is now replaced by the creation of a URLRequest value-type using #if branching. We may want to factorize this code into a helper function in the test class though. But this may need to convert all NSURLRequest to NSMutableURLRequest to have only one method call.

    Use NSURL's path in isPath instead of URL's path

    The path property on URL does not behave as the one in NSURL. In URL, the path is not truncated at the first semicolon. This has the effect to make the actual tests fail. So to fix this, I used NSURL's path.

    For this pull request, I used the swift version of Xcode 8 beta 4.

    I hope this helps!

    opened by Liquidsoul 25
  • OHHTTPStubs not mocking when Alamofire request made in AppDelegate

    OHHTTPStubs not mocking when Alamofire request made in AppDelegate

    Not sure if I should post this issue here or over at Alamofire

    I have a unit test that stubs httpbin.org, and then it makes an Alamofire request. The request is stubbed as expected.

    If I then add an Alamofire request to AppDelegate, the stub in the unit test stops mocking and instead the Alamofire request in the unit test calls the actual service.

    I have a sample here https://github.com/iwllyu/test-ohhttpstubs

    • Swift 2.0
    • Xcode 7.0.1 (7A1001)
    • OHHTTPStubs 4.3.0 with swift support
    • Alamofire 2.0.2
    • Quick/Nimble
    Question Solution available 
    opened by iwllyu 25
  • Adding Swift Package Manager Support

    Adding Swift Package Manager Support

    Updating gitignore. Adding Package.swift Adding Swift tests, getting all builds working. Downgrading swift package version to be compatible with Xcode 9.1. Disabling xcode 9.1 tests and redirect tests in other xcode versions. Changing iPhone types depending on Xcode version. Passing conditional compilation flags to swift test to disable redirect tests in CI. Bumping podspec version. Cleaning up podspec. Updating example projects. Adding SPM Example. Moving Example Stubs to shared folder. Adding building example apps to CI. Adding Carthage builds to CI. Updating rake file for SPM tests. Passing Swift Versions to carthage. Updating SPM example to use URLSession instead of URLConnection. Updating documentation.

    Checklist

    • [x] I've checked that all new and existing tests pass
    • [x] I've updated the documentation if necessary
    • [x] I've added an entry in the CHANGELOG to credit myself

    Description

    This PR is for adding Swift Package Manager support.

    Motivation and Context

    Apple integrated Swift Package Manager into Xcode 11 this year and these are the changes to support it.

    File Structure:

    The apple docs tell us to have the Package.swift at the root of the repository.

    To turn your existing component into a Swift package, you don’t need to create a new Swift package from scratch. Instead, keep your existing project and add a README.md and a Package.swift file inside the root directory of your library project to turn your library into a Swift package.

    While SPM does not require a specific structure, OHHTTPStubs's SPM support will be easier to maintain if we conform to the standard style of foldering in SPM: Sources and Tests at the root of the repo, and then folders matching the names of the targets inside of those. This required moving most of the files up a level by removing the OHHTTPStubs folder that was previously at the root of the project and also renaming UnitTests to become Tests.

    The pod specs were updated for the new file structure. To validate them, I ran a pod install in the ObjC and Swift Example projects, I verified that the same files exist, their visibility did not change, and that the example projects still work as expected.

    The OHHTTPStub project was also updated for the new file structure. To validate it, I ran unit tests on several Xcode versions (9.1, 10.1, 10.2, 11).

    Package Naming:

    I went through several revisions on the right design for the package targets.

    Original Design

    I originally went down the path of trying to recreate the subspecs that exist in our Cocoapods integration. This was a bit painful, but worked. Once I started on the SPM example project, I saw the awkwardness of having to import each of the targets to my swift example code.

    Screen Shot 2019-08-10 at 8 12 49 PM
    Second Design

    I then decided to modify the package design to be 2 targets: OHHTTPStubs and OHHTTPStubsSwift, but ran into problems with this approach also.

    As soon as I created the OHHTTPStubs target, I started receiving warnings about certain headers not being included in our OHHTTPStubs.h umbrella header. SPM started seeing this existing file as our umbrella header and wasn't generating one on its own anymore. I was tempted to rename our OHHTTPStubs.h file to be something else to get SPM to create an umbrella header again, but wanted to retain backwards compatibility with this PR.

    Final Design

    I then changed the design to be 2 targets: OHHTTPStubsCore and OHHTTPStubsSwift.

    Importing these in Swift will look like this:

    Screen Shot 2019-08-12 at 8 48 54 AM

    Example Projects:

    • A Swift Package Manager project with OHHTTPStubs integration (Xcode-11 beta 5) was added to the Examples/SwiftPackageManager folder. This example project uses URLSession APIs.
    • The Stubs folder and files used in the example apps is now shared to remove the previously duplicate stub files in each example.

    CI Support:

    I added a lot more (is this overkill?) travis tasks in this PR. These are the new tasks:

    • xcodebuild test in Xcode 11 for iOS Static, iOS Dynamic, MacOS, and tvOS
    • swift test in Xcode 10.1, 10.2, 11.
    • carthage build commands in 9.1, 10.1, 10.2, 11 and several versions of swift: 3.2, 4.0, 4.1, 4.2, 5.0, 5.1.
    • xcodebuild build to build all example projects in Xcode 11.

    Other:

    opened by jeffctown 22
  • Fix redirect handling to respect RFC and HTTP/1.1 RFC 7538

    Fix redirect handling to respect RFC and HTTP/1.1 RFC 7538

    Before this change, a POST request redirected with status code 307 or 308 would become a request with GET method. This check-in changes the behavior to retain the HTTP method in the case of 307/308 redirect

    Checklist

    • [X] I've checked that all new and existing tests pass
    • [ N/A ] I've updated the documentation if necessary
    • [X] I've added an entry in the CHANGELOG to credit myself

    Description

    Motivation and Context

    inadherence to RFC and HTTP specs.

    Fixes #262

    I ran existing NSURLSession tests. TODO: Create a test case to handle these cases. Will require some help from @AliSoftware to do so

    Thanks to my colleague @sashra for finding this!

    Work In Progress (WIP) 
    opened by mikelupo 22
  • Trouble getting OHHTTPStubs working with a custom Alamofire Session Manager.

    Trouble getting OHHTTPStubs working with a custom Alamofire Session Manager.

    New Issue Checklist

    Environment

    • version of OHHTTPStubs: 6.0.0
    • integration method you are using:
      • [x] Cocoapods
      • [ ] Carthage
      • [ ] submodule
      • [ ] other
    • version of the tool you use: 1.2.1

    Issue Description

    I was trying to test my own CocoaPods library web services with OHHTTPStubs. All the service is built on top of Alamofire through a singleton which creates its own Alamofire.SessionManager created in the following way:

    public var configuration: SessionManagerConfiguration = SessionManagerConfiguration.default {
            didSet(newValue) {
                let configuration = URLSession.shared.configuration
                if let token = UserDefaults.standard.string(forKey: newValue.userDefaultsTokenKey) {
                    configuration.httpAdditionalHeaders = ["token": token]
                    configuration.urlCache = nil
                }
                let delegate = Alamofire.SessionDelegate()
                let session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
                self._sessionManager = Alamofire.SessionManager(session: session, delegate: delegate)!
                
                self.initializeObservables()
            }
        }
    

    This is being correctly invoked in my beforeSuite{ } method when I create the singleton and set the configuration at the same time:

    SessionManager.shared.configuration = SessionManagerConfiguration(withInvalidAuthenticationNotificationName: Notification.Name(rawValue: "testInvalidAuthenticationName"), invalidAuthenticationCode: 1500, userDefaultsTokenKey: "testTokenKey", baseURL: self.baseURL)
    

    Where baseURL is just a random URL that I want to stub certain endpoints that satisfy my services, like this:

            describe("User Operations Spec") {
                
                it("Should retrieve an user") {
                    
                    OHHTTPStubs.setEnabled(true, for: SessionManager.shared.sessionManager.session.configuration)
                    
                    self.userDetailStub = stub(condition: isHost(self.baseURL)) {
                        _ in
                        let stubData = self.loadUserStub()
                        return OHHTTPStubsResponse(data: stubData, statusCode: 200, headers: nil)
                    }
                    
                    var user: User!
                    
                    SessionManager.shared.service.user.user(.internet)
                        .observeOn(MainScheduler.instance)
                        .subscribe(onNext: {
                            _user in
                            user = _user
                        })
                        .disposed(by: self.disposeBag)
                    
                    expect(user).toEventuallyNot(beNil(), timeout: 5)
                    expect(user.id_hash.int64Value) == 1446546480781
                }
            }
    

    After running the test, the expectation did not get fulfilled so the tests fails, as shown in the lines below.

    Complete output when you encounter the issue (if any)
    /Users/GabrielVillarrubia/Documents/Private Pods/EbmCore/Example/Tests/User Operation Specs.swift:76: error: -[EbmCore_Tests.UserOperationSpecs User_Operations_Spec__Should_retrieve_an_user] : expected to eventually not be nil, got <nil>
    
    fatal error: unexpectedly found nil while unwrapping an Optional value
    

    There's something obvious that I'm skipping on this? There's no host app due to the fact that this is a CocoaPods framework's test suite.

    Thank you very much and keep it up with the great work with this library!

    opened by minuscorp 22
  • Fix OHHTTPStubsProtocol threading

    Fix OHHTTPStubsProtocol threading

    Per Apple docs https://developer.apple.com/library/prerelease/ios/samplecode/CustomHTTPProtocol/Listings/Read_Me_About_CustomHTTPProtocol_txt.html :

    In addition, an NSURLProtocol subclass is expected to call the various methods of the NSURLProtocolClient protocol from the client thread
    

    So, instead of having callbacks happen on a background queue, OHHTTPStubsProtocol need to capture the executing runloop and execute callbacks from that runloop. This is a requirement of NSURLProtocol.

    -- Twitter uses OHHTTPStubs for certain unit tests and we have made this change on our local fork. Providing the fix here for the benefit of all.

    opened by NSProgrammer 22
  • how do i use it

    how do i use it

    New Issue Checklist

    Environment

    • version of OHHTTPStubs: [LIB VERSION HERE]
    • integration method you are using:
      • [ ] Cocoapods
      • [ ] Carthage
      • [ ] submodule
      • [ ] other
    • version of the tool you use: [INSERT VERSION HERE]

    Issue Description

    [DESCRIBE YOUR ISSUE HERE]

    Complete output when you encounter the issue (if any)
    [INSERT OUTPUT HERE]
    
    opened by phonefixnicole 0
  • Export OHHTTPStubs from OHHTTPStubsSwift

    Export OHHTTPStubs from OHHTTPStubsSwift

    Checklist

    • [ ] I've checked that all new and existing tests pass
    • [ ] I've updated the documentation if necessary
    • [ ] I've added an entry in the CHANGELOG to credit myself

    Description

    Export OHHTTPStubs from OHHTTPStubsSwift using @_exported so that users doesn't need to import both of them.

    Motivation and Context

    Previously SwiftPM users should import both OHHTTPStubs and OHHTTPStubs, contrary to CocoaPods users who need to import only OHHTTPStubs. This difference is small but an obstacle for migrating to Swift Package Manager.

    1. Firstly I removed import OHHTTPStubs statement from Tests/OHHTTPStubsSwiftTests/SwiftHelperTests.swift. This change made tests fail.
    2. Then add @_exported modifier to import statement, then the test passed.
    opened by manicmaniac 0
  • Xcode 14 - Warnings related to iOS 11 support (Swift Package Manager)

    Xcode 14 - Warnings related to iOS 11 support (Swift Package Manager)

    Checklist

    • [x] I've checked that all new and existing tests pass
    • [x] I've updated the documentation if necessary
    • [x] I've added an entry in the CHANGELOG to credit myself

    Description

    Hi, I would like to contribute fixing a recent warning.

    The new Xcode 14 uses next SDKs as base: iOS 11.0, macOS 10.13, watchOS 4.0 and tvOS 11.0. Compiling in this Xcode shows a warning. Handle this restrictions relying on swift version (which is also vinculated to each Xcode version).

    Regards and comments welcomed

    Motivation and Context

    Fixes a warning

    Run project tests and compile on each platform.

    opened by kikeenrique 0
  • OHHTPStubs frameworks: Put Headers phase before Sources phase.

    OHHTPStubs frameworks: Put Headers phase before Sources phase.

    Checklist

    • [ X ] I've checked that all new and existing tests pass
    • [ X ] I've updated the documentation if necessary
    • [ X ] I've added an entry in the CHANGELOG to credit myself

    Motivation and Context

    On Xcode 13.3 sometimes an error about cycle dependencies is emitted. The fix to this is to put the Headers build phase before Sources build phase.

    opened by byohay 1
  • Fluent API for stubbing

    Fluent API for stubbing

    It'd be really nice if there was a fluent API for stubbing. I personally feel this drastically helps readability and has the added benefit of making it very simple to return different responses for the same condition.

    Ideal API (in my head):

        func testExample() async throws {
            let expectedData = try XCTUnwrap(UUID().uuidString.data(using: .utf8))
            let secondData = try XCTUnwrap(UUID().uuidString.data(using: .utf8))
            StubResponse(on: isHost("www.someapi.com") && isMethodGET() ) { req in
                HTTPStubsResponse(data: expectedData, statusCode: 500, headers: nil)
            }.thenRespond(on: isHost("www.someapi.com") && isMethodGET() ) { req in
                HTTPStubsResponse(data: secondData, statusCode: 400, headers: nil)
            }
    
            let (data, response) = try await URLSession.shared.data(from: URL(string: "https://www.someapi.com")!)
            XCTAssertEqual((response as? HTTPURLResponse)?.statusCode, 500) // first respond with a 500
            XCTAssertEqual(data, expectedData)
    
            let (data2, response2) = try await URLSession.shared.data(from: URL(string: "https://www.someapi.com")!)
            XCTAssertEqual((response2 as? HTTPURLResponse)?.statusCode, 400) // then respond with a 400
            XCTAssertEqual(data2, secondData)
    
            let (data3, response3) = try await URLSession.shared.data(from: URL(string: "https://www.someapi.com")!)
            XCTAssertEqual((response3 as? HTTPURLResponse)?.statusCode, 400) // 400 response stays stubbed, cause that was the last one
            XCTAssertEqual(data3, secondData)
        }
    

    WIP - (The thing I usually rebuild)

    I thought I'd share code I often rewrite when I pull in this library so that others might benefit. It has some drawbacks, it's not particularly efficient, and it's a little questionable how it removes stubs, but I think it's a useful copy/paste if you also like this sort of thing.

    import OHHTTPStubs
    import OHHTTPStubsSwift
    
    final class StubResponse {
        var stubs: [(condition: HTTPStubsTestBlock, response: HTTPStubsResponseBlock)] = []
        @discardableResult convenience init(on condition: @escaping HTTPStubsTestBlock, with response: @escaping HTTPStubsResponseBlock) {
            self.init(stubs: [(condition, response)])
        }
    
        private init(stubs: [(condition: HTTPStubsTestBlock, response: HTTPStubsResponseBlock)]) {
            self.stubs = stubs
            stub { req in
                let filtered = self.stubs.enumerated().filter { $0.element.condition(req) }
                return !filtered.isEmpty
            } response: { req in
                let filtered = self.stubs.enumerated().filter { $0.element.condition(req) }
                guard let first = filtered.first else { fatalError("No stub response found, something bad happened") }
                defer {
                    if filtered.count > 1, let first = filtered.first {
                        self.stubs.remove(at: first.offset)
                    }
                }
                return first.element.response(req)
            }
        }
    
        @discardableResult func thenRespond(on condition: @escaping HTTPStubsTestBlock, with response: @escaping HTTPStubsResponseBlock) -> Self {
            Self(stubs: stubs.appending((condition, response)))
        }
    }
    
    
    extension Array {
        fileprivate func appending(_ element: Element) -> Self {
            var copy = self
            copy.append(element)
            return copy
        }
    }
    
    

    I would submit a PR but I'm not sure if others would find this useful and didn't want to spend time resolving the issues mentioned unless this is useful to anybody other than me.

    opened by Tyler-Keith-Thompson 0
  • OHHTTPStubs with SPM in Xcode 12.5

    OHHTTPStubs with SPM in Xcode 12.5

    New Issue Checklist

    Environment

    • version of OHHTTPStubs: 9.1.0
    • integration method you are using:
      • [ ] Cocoapods
      • [ ] Carthage
      • [ ] submodule
      • [x] other (SPM)
    • version of the tool you use: Xcode 12.5.1

    Issue Description

    Stubs are being added but test condition block is never called. I am using Xcode 12.5.1 and thus Swift 5.4.2. I think I have an identical setup to #346 because I am also using UI tests without a host application.

    opened by LemonSpike 0
Releases(9.1.0)
Owner
Olivier Halligon
iOS architect & Swift lover. OSS enthusiast.
Olivier Halligon
This is a Swift port of Ruby's Faker library that generates fake data.

This is a Swift port of Ruby's Faker library that generates fake data. Are you still bothered with meaningless randomly character strings? Just relax

Vadym Markov 1.6k Jan 3, 2023
Fake iPhone real devices location using this small app

Project Title iPhone IP Spoofer for Real Devices. Description IP, or internet protocol, is a string of numbers that identifies your iPhone, iPad, or w

Ebahim Mostafa 4 Sep 20, 2022
Test-To-Do-List - Test To Do List with core data

test-To-Do-List This is my first pet project with core data Launch screen Main s

Artem 0 Feb 26, 2022
This is a simple test app getting data from network to practice a tad bit.

test This is a simple test app getting data from network to practice a tad bit. Start Nothing fancy, no CocoaPods, just clone and run! Architecture Ju

null 1 Oct 9, 2021
Kfm-ios-test - Test online for iOS Developer position in Kimia Farma or PT. Buana Varia Komputama

kfm-ios-test Kimia Farma Mobile iOS Test Test online for iOS Developer position

Erwindo Sianipar 3 Feb 23, 2022
Mock Alamofire and URLSession requests without touching your code implementation

Mocker is a library written in Swift which makes it possible to mock data requests using a custom URLProtocol. Features Requirements Usage Activating

WeTransfer 898 Dec 26, 2022
Automatic testing of your Pull Requests on GitHub and BitBucket using Xcode Server. Keep your team productive and safe. Get up and running in minutes. @buildasaur

Buildasaur Automatic testing of your Pull Requests on GitHub and BitBucket using Xcode Server. Keep your team productive and safe. Get up and running

Buildasaurs 774 Dec 11, 2022
This repository accompanies Test-Driven Development in Swift: Compile Better Code with XCTest and TDD

Apress Source Code This repository accompanies Test-Driven Development in Swift: Compile Better Code with XCTest and TDD by Gio Lodi (Apress, 2021). D

Apress 57 Jan 1, 2023
This repo holds the code for Dubizzle & Bayut test App

DubizzleClassified This repo holds the code for Dubizzle & Bayut test App About App This is a simple app which basically fetches item list from the gi

Ghassan 0 Jun 2, 2022
An elegant library for stubbing HTTP requests with ease in Swift

Mockingjay An elegant library for stubbing HTTP requests in Swift, allowing you to stub any HTTP/HTTPS using NSURLConnection or NSURLSession. That inc

Kyle Fuller 1.5k Dec 3, 2022
AutoMocker is a Swift framework that leverages the type system to let you easily create mocked instances of your data types.

AutoMocker Context AutoMocker is a Swift framework that leverages the type system to let you easily create mocked instances of your data types. Here's

Vincent Pradeilles 39 May 19, 2022
Creation of data model easily, with no headache.

DataFixture Create data models easily, with no headache. DataFixture is a convenient way to generate new data for testing / seeding your Realm Databas

Andrea Del Fante 2 Jul 12, 2022
BDD Framework and test runner for Swift projects and playgrounds

Spectre Special Executive for Command-line Test Running and Execution. A behavior-driven development (BDD) framework and test runner for Swift project

Kyle Fuller 392 Jan 1, 2023
I built this application with unit testing and test-driven development to understand TDD theory and practice

TestDrivenDevelopment Description I built this application with unit testing and test-driven development to understand TDD theory and practice, to wri

null 1 Dec 21, 2021
Test task application based on Swift using CoreData, Alamofire, AlamofireImage and CocoaPods

iTunes Search Test task application based on Swift using CoreData, Alamofire, AlamofireImage and CocoaPods Features ?? Searching music albums by name

Alexander Zhukov 0 Oct 31, 2021
test ios UnitTest and UITest

github_actions Bundlerの導入 fastlaneやiOSパッケージマネージャであるCocoaPodsはRubyのライブラリ 開発チームで使用するバージョンを揃えるためにBundlerを導入する bundlerのインストール gem install bundler Gemfile

SUGY 0 Nov 3, 2021
The XCTest Project, A Swift core library for providing unit test support

XCTest The XCTest library is designed to provide a common framework for writing unit tests in Swift, for Swift packages and applications. This version

Apple 1k Jan 4, 2023
Test Library for Swift's Error Handling

CatchingFire CatchingFire is a Swift test framework, which helps making expectations against the error handling of your code. It provides for this pur

Marius Rackwitz 75 May 16, 2022
Test case project for mackolik

Mackolik - iOS Developer - Test Case Gökhan Mandacı 28 Oct 2021 I developed a two-page app and a general purpose drop down widget for the Mackolik Tes

Gökhan Mandacı 0 Oct 28, 2021