Skip to content

Commit 60a9bff

Browse files
authored
feat: Global mode to choose only to mock registered routes (#84)
* 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
1 parent aeec122 commit 60a9bff

File tree

3 files changed

+100
-10
lines changed

3 files changed

+100
-10
lines changed

MockerTests/MockerTests.swift

+54
Original file line numberDiff line numberDiff line change
@@ -441,4 +441,58 @@ final class MockerTests: XCTestCase {
441441

442442
waitForExpectations(timeout: 10.0, handler: nil)
443443
}
444+
445+
/// It should process unknown URL
446+
func testMockerOptoutMode() {
447+
Mocker.mode = .optout
448+
449+
let mockedURL = URL(string: "www.google.com")!
450+
let ignoredURL = URL(string: "www.wetransfer.com")!
451+
let unknownURL = URL(string: "www.netflix.com")!
452+
453+
// Mocking
454+
Mock(url: mockedURL, dataType: .json, statusCode: 200, data: [.get: Data()])
455+
.register()
456+
457+
// Ignoring
458+
Mocker.ignore(ignoredURL)
459+
460+
// Checking mocked URL are processed by Mocker
461+
XCTAssertTrue(MockingURLProtocol.canInit(with: URLRequest(url: mockedURL)))
462+
// Checking ignored URL are not processed by Mocker
463+
XCTAssertFalse(MockingURLProtocol.canInit(with: URLRequest(url: ignoredURL)))
464+
465+
// Checking unknown URL are processed by Mocker (.optout mode)
466+
XCTAssertTrue(MockingURLProtocol.canInit(with: URLRequest(url: unknownURL)))
467+
}
468+
469+
/// It should not process unknown URL
470+
func testMockerOptinMode() {
471+
Mocker.mode = .optin
472+
473+
let mockedURL = URL(string: "www.google.com")!
474+
let ignoredURL = URL(string: "www.wetransfer.com")!
475+
let unknownURL = URL(string: "www.netflix.com")!
476+
477+
// Mocking
478+
Mock(url: mockedURL, dataType: .json, statusCode: 200, data: [.get: Data()])
479+
.register()
480+
481+
// Ignoring
482+
Mocker.ignore(ignoredURL)
483+
484+
// Checking mocked URL are processed by Mocker
485+
XCTAssertTrue(MockingURLProtocol.canInit(with: URLRequest(url: mockedURL)))
486+
// Checking ignored URL are not processed by Mocker
487+
XCTAssertFalse(MockingURLProtocol.canInit(with: URLRequest(url: ignoredURL)))
488+
489+
// Checking unknown URL are not processed by Mocker (.optin mode)
490+
XCTAssertFalse(MockingURLProtocol.canInit(with: URLRequest(url: unknownURL)))
491+
}
492+
493+
/// Default mode should be .optout
494+
func testDefaultMode() {
495+
/// Checking default mode
496+
XCTAssertEqual(.optout, Mocker.mode)
497+
}
444498
}

README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,25 @@ Mock(url: URL(string: "https://wetransfer.com/redirect")!, dataType: .json, stat
181181
```
182182

183183
##### Ignoring URLs
184-
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:
184+
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:
185185

186186
```swift
187187
let ignoredURL = URL(string: "www.wetransfer.com")!
188188
Mocker.ignore(ignoredURL)
189189
```
190190

191+
However if you need the Mocker to catch only mocked URLs and ignore every other URL, you can set the `mode` attribute to `.optin`.
192+
193+
```swift
194+
Mocker.mode = .optin
195+
```
196+
197+
If you want to set the original mode back, you have just to set it to `.optout`.
198+
199+
```swift
200+
Mocker.mode = .optout
201+
```
202+
191203
##### Mock errors
192204

193205
You can request a `Mock` to return an error, allowing testing of error handling.

Sources/Mocker.swift

+33-9
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,35 @@ public struct Mocker {
3232
case http1_1 = "HTTP/1.1"
3333
case http2_0 = "HTTP/2.0"
3434
}
35-
35+
36+
/// The way Mocker handles unregistered urls
37+
public enum Mode {
38+
/// The default mode: only URLs registered with the `ignore(_ url: URL)` method are ignored for mocking.
39+
///
40+
/// - Registered mocked URL: Mocked.
41+
/// - Registered ignored URL: Ignored by Mocker, default process is applied as if the Mocker doesn't exist.
42+
/// - Any other URL: Raises an error.
43+
case optout
44+
45+
/// Only registered mocked URLs are mocked, all others pass through.
46+
///
47+
/// - Registered mocked URL: Mocked.
48+
/// - Any other URL: Ignored by Mocker, default process is applied as if the Mocker doesn't exist.
49+
case optin
50+
}
51+
52+
/// The mode defines how unknown URLs are handled. Defaults to `optout` which means requests without a mock will fail.
53+
public static var mode: Mode = .optout
54+
3655
/// The shared instance of the Mocker, can be used to register and return mocks.
3756
internal static var shared = Mocker()
38-
57+
3958
/// The HTTP Version to use in the mocked response.
4059
public static var httpVersion: HTTPVersion = HTTPVersion.http1_1
41-
60+
4261
/// The registrated mocks.
4362
private(set) var mocks: [Mock] = []
44-
63+
4564
/// URLs to ignore for mocking.
4665
public var ignoredURLs: [URL] {
4766
ignoredRules.map { $0.urlToIgnore }
@@ -56,7 +75,7 @@ public struct Mocker {
5675
// Whenever someone is requesting the Mocker, we want the URL protocol to be activated.
5776
URLProtocol.registerClass(MockingURLProtocol.self)
5877
}
59-
78+
6079
/// Register new Mocked data. If a mock for the same URL and HTTPMethod exists, it will be overwritten.
6180
///
6281
/// - Parameter mock: The Mock to be registered for future requests.
@@ -67,7 +86,7 @@ public struct Mocker {
6786
shared.mocks.append(mock)
6887
}
6988
}
70-
89+
7190
/// Register an URL to ignore for mocking. This will let the URL work as if the Mocker doesn't exist.
7291
///
7392
/// - Parameter url: The URL to mock.
@@ -78,14 +97,19 @@ public struct Mocker {
7897
shared.ignoredRules.append(rule)
7998
}
8099
}
81-
100+
82101
/// 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.
83102
///
84103
/// - Parameter url: The URL to check for.
85104
/// - Returns: `true` if it should be mocked, `false` if the URL is registered as ignored.
86105
public static func shouldHandle(_ url: URL) -> Bool {
87106
shared.queue.sync {
88-
return !shared.ignoredRules.contains(where: { $0.shouldIgnore(url) })
107+
switch mode {
108+
case .optout:
109+
return !shared.ignoredRules.contains(where: { $0.shouldIgnore(url) })
110+
case .optin:
111+
return shared.mocks.contains(where: { $0.url == url })
112+
}
89113
}
90114
}
91115

@@ -95,7 +119,7 @@ public struct Mocker {
95119
shared.mocks.removeAll()
96120
}
97121
}
98-
122+
99123
/// Retrieve a Mock for the given request. Matches on `request.url` and `request.httpMethod`.
100124
///
101125
/// - Parameter request: The request to search for a mock.

0 commit comments

Comments
 (0)