Skip to content

Commit

Permalink
feat: Global mode to choose only to mock registered routes (#84)
Browse files Browse the repository at this point in the history
* feat: Added a global mode selection to be able to only mock registered routes, and let every other url to be processed as if the Mocker is not present.

* refactor: Reorganizing subtype position and fixing documentation following @AvdLee advices.

* fix: Added unit tests to Mocker mode

* fix: Fixing SwiftLint rule `switch_case_on_newline`

* fix: Updated documentation chapter on Ignoring URLs to add the new mode

* fix: typo
  • Loading branch information
letatas authored Feb 24, 2021
1 parent aeec122 commit 60a9bff
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 10 deletions.
54 changes: 54 additions & 0 deletions MockerTests/MockerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,58 @@ final class MockerTests: XCTestCase {

waitForExpectations(timeout: 10.0, handler: nil)
}

/// It should process unknown URL
func testMockerOptoutMode() {
Mocker.mode = .optout

let mockedURL = URL(string: "www.google.com")!
let ignoredURL = URL(string: "www.wetransfer.com")!
let unknownURL = URL(string: "www.netflix.com")!

// Mocking
Mock(url: mockedURL, dataType: .json, statusCode: 200, data: [.get: Data()])
.register()

// Ignoring
Mocker.ignore(ignoredURL)

// Checking mocked URL are processed by Mocker
XCTAssertTrue(MockingURLProtocol.canInit(with: URLRequest(url: mockedURL)))
// Checking ignored URL are not processed by Mocker
XCTAssertFalse(MockingURLProtocol.canInit(with: URLRequest(url: ignoredURL)))

// Checking unknown URL are processed by Mocker (.optout mode)
XCTAssertTrue(MockingURLProtocol.canInit(with: URLRequest(url: unknownURL)))
}

/// It should not process unknown URL
func testMockerOptinMode() {
Mocker.mode = .optin

let mockedURL = URL(string: "www.google.com")!
let ignoredURL = URL(string: "www.wetransfer.com")!
let unknownURL = URL(string: "www.netflix.com")!

// Mocking
Mock(url: mockedURL, dataType: .json, statusCode: 200, data: [.get: Data()])
.register()

// Ignoring
Mocker.ignore(ignoredURL)

// Checking mocked URL are processed by Mocker
XCTAssertTrue(MockingURLProtocol.canInit(with: URLRequest(url: mockedURL)))
// Checking ignored URL are not processed by Mocker
XCTAssertFalse(MockingURLProtocol.canInit(with: URLRequest(url: ignoredURL)))

// Checking unknown URL are not processed by Mocker (.optin mode)
XCTAssertFalse(MockingURLProtocol.canInit(with: URLRequest(url: unknownURL)))
}

/// Default mode should be .optout
func testDefaultMode() {
/// Checking default mode
XCTAssertEqual(.optout, Mocker.mode)
}
}
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,25 @@ Mock(url: URL(string: "https://wetransfer.com/redirect")!, dataType: .json, stat
```

##### Ignoring URLs
As the Mocker catches all URLs when registered, you might end up with a `fatalError` thrown in cases you don't need a mocked request. In that case you can ignore the URL:
As the Mocker catches all URLs by default when registered, you might end up with a `fatalError` thrown in cases you don't need a mocked request. In that case you can ignore the URL:

```swift
let ignoredURL = URL(string: "www.wetransfer.com")!
Mocker.ignore(ignoredURL)
```

However if you need the Mocker to catch only mocked URLs and ignore every other URL, you can set the `mode` attribute to `.optin`.

```swift
Mocker.mode = .optin
```

If you want to set the original mode back, you have just to set it to `.optout`.

```swift
Mocker.mode = .optout
```

##### Mock errors

You can request a `Mock` to return an error, allowing testing of error handling.
Expand Down
42 changes: 33 additions & 9 deletions Sources/Mocker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,35 @@ public struct Mocker {
case http1_1 = "HTTP/1.1"
case http2_0 = "HTTP/2.0"
}


/// The way Mocker handles unregistered urls
public enum Mode {
/// The default mode: only URLs registered with the `ignore(_ url: URL)` method are ignored for mocking.
///
/// - Registered mocked URL: Mocked.
/// - Registered ignored URL: Ignored by Mocker, default process is applied as if the Mocker doesn't exist.
/// - Any other URL: Raises an error.
case optout

/// Only registered mocked URLs are mocked, all others pass through.
///
/// - Registered mocked URL: Mocked.
/// - Any other URL: Ignored by Mocker, default process is applied as if the Mocker doesn't exist.
case optin
}

/// The mode defines how unknown URLs are handled. Defaults to `optout` which means requests without a mock will fail.
public static var mode: Mode = .optout

/// The shared instance of the Mocker, can be used to register and return mocks.
internal static var shared = Mocker()

/// The HTTP Version to use in the mocked response.
public static var httpVersion: HTTPVersion = HTTPVersion.http1_1

/// The registrated mocks.
private(set) var mocks: [Mock] = []

/// URLs to ignore for mocking.
public var ignoredURLs: [URL] {
ignoredRules.map { $0.urlToIgnore }
Expand All @@ -56,7 +75,7 @@ public struct Mocker {
// Whenever someone is requesting the Mocker, we want the URL protocol to be activated.
URLProtocol.registerClass(MockingURLProtocol.self)
}

/// Register new Mocked data. If a mock for the same URL and HTTPMethod exists, it will be overwritten.
///
/// - Parameter mock: The Mock to be registered for future requests.
Expand All @@ -67,7 +86,7 @@ public struct Mocker {
shared.mocks.append(mock)
}
}

/// Register an URL to ignore for mocking. This will let the URL work as if the Mocker doesn't exist.
///
/// - Parameter url: The URL to mock.
Expand All @@ -78,14 +97,19 @@ public struct Mocker {
shared.ignoredRules.append(rule)
}
}

/// Checks if the passed URL should be handled by the Mocker. If the URL is registered to be ignored, it will not handle the URL.
///
/// - Parameter url: The URL to check for.
/// - Returns: `true` if it should be mocked, `false` if the URL is registered as ignored.
public static func shouldHandle(_ url: URL) -> Bool {
shared.queue.sync {
return !shared.ignoredRules.contains(where: { $0.shouldIgnore(url) })
switch mode {
case .optout:
return !shared.ignoredRules.contains(where: { $0.shouldIgnore(url) })
case .optin:
return shared.mocks.contains(where: { $0.url == url })
}
}
}

Expand All @@ -95,7 +119,7 @@ public struct Mocker {
shared.mocks.removeAll()
}
}

/// Retrieve a Mock for the given request. Matches on `request.url` and `request.httpMethod`.
///
/// - Parameter request: The request to search for a mock.
Expand Down

0 comments on commit 60a9bff

Please sign in to comment.