Skip to content

Commit c285f16

Browse files
Merge pull request #107 from dbsystel/improved-mock
Improves NetworkServiceMock
2 parents 19dba97 + a132c52 commit c285f16

File tree

3 files changed

+109
-53
lines changed

3 files changed

+109
-53
lines changed

Source/NetworkServiceMock.swift

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ import Foundation
2525
import Dispatch
2626

2727
struct NetworkServiceMockCallback {
28-
let onErrorCallback: ((NetworkError) -> Void)?
29-
let onTypedSuccess: ((Any, HTTPURLResponse) -> Void)?
28+
let onErrorCallback: (NetworkError) -> Void
29+
let onTypedSuccess: (Any, HTTPURLResponse) throws -> Void
3030

3131
init<Result>(resource: Resource<Result>, onCompletionWithResponse: @escaping (Result, HTTPURLResponse) -> Void, onError: @escaping (NetworkError) -> Void) {
3232
onTypedSuccess = { anyResult, response in
3333
guard let typedResult = anyResult as? Result else {
34-
fatalError("Extected type of \(Result.self) but got \(anyResult.self)")
34+
throw NetworkServiceMock.Error.typeMismatch
3535
}
3636
onCompletionWithResponse(typedResult, response)
3737
}
@@ -97,6 +97,20 @@ struct NetworkServiceMockCallback {
9797
- seealso: `NetworkService`
9898
*/
9999
public final class NetworkServiceMock: NetworkService {
100+
101+
public enum Error: Swift.Error, CustomDebugStringConvertible {
102+
case missingRequest
103+
case typeMismatch
104+
105+
public var debugDescription: String {
106+
switch self {
107+
case .missingRequest:
108+
return "Could not return because no request"
109+
case .typeMismatch:
110+
return "Return type does not match requested type"
111+
}
112+
}
113+
}
100114

101115
/// Count of all started requests
102116
public var requestCount: Int {
@@ -107,6 +121,10 @@ public final class NetworkServiceMock: NetworkService {
107121
public var lastRequest: URLRequest? {
108122
return lastRequests.last
109123
}
124+
125+
public var pendingRequestCount: Int {
126+
return callbacks.count
127+
}
110128

111129
/// All executed requests.
112130
public private(set) var lastRequests: [URLRequest] = []
@@ -161,19 +179,27 @@ public final class NetworkServiceMock: NetworkService {
161179
///
162180
/// - Parameters:
163181
/// - error: the error which gets passed to the caller
164-
public func returnError(with error: NetworkError) {
165-
callbacks.removeFirst().onErrorCallback?(error)
182+
///
183+
/// - Throws: An error of type `NetworkServiceMock.Error`
184+
public func returnError(with error: NetworkError) throws {
185+
guard !callbacks.isEmpty else {
186+
throw Error.missingRequest
187+
}
188+
callbacks.removeFirst().onErrorCallback(error)
166189
}
167190

168191
/// Will return a successful request, by using the given type `T` as serialized result of a request.
169192
///
170-
/// **Warning:** This will crash if type `T` does not match your expected ResponseType of your current request
171-
///
172193
/// - Parameters:
173194
/// - data: the mock response from the server. `Data()` by default
174195
/// - httpResponse: the mock `HTTPURLResponse` from the server. `HTTPURLResponse()` by default
175-
public func returnSuccess<T>(with serializedResponse: T, httpResponse: HTTPURLResponse = HTTPURLResponse()) {
176-
callbacks.removeFirst().onTypedSuccess?(serializedResponse, httpResponse)
196+
///
197+
/// - Throws: An error of type `NetworkServiceMock.Error`
198+
public func returnSuccess<T>(with serializedResponse: T, httpResponse: HTTPURLResponse = HTTPURLResponse()) throws {
199+
guard !callbacks.isEmpty else {
200+
throw Error.missingRequest
201+
}
202+
try callbacks.removeFirst().onTypedSuccess(serializedResponse, httpResponse)
177203
}
178204

179205
}

Tests/NetworkServiceMockTest.swift

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class NetworkServiceMockTest: XCTestCase {
5252
XCTAssertEqual(networkServiceMock.lastRequests, [resource.request, resource.request])
5353
}
5454

55-
func testReturnSuccessWithData() {
55+
func testReturnSuccessWithData() throws {
5656
//Given
5757
var capturedResult: Int?
5858
var executionCount: Int = 0
@@ -62,14 +62,14 @@ class NetworkServiceMockTest: XCTestCase {
6262
capturedResult = result
6363
executionCount += 1
6464
}, onError: { _ in })
65-
networkServiceMock.returnSuccess(with: 1)
65+
try networkServiceMock.returnSuccess(with: 1)
6666

6767
//Then
6868
XCTAssertEqual(capturedResult, 1)
6969
XCTAssertEqual(executionCount, 1)
7070
}
7171

72-
func testCorrectOrderOfReturnSuccessWithDataForMultipleRequests() {
72+
func testCorrectOrderOfReturnSuccessWithDataForMultipleRequests() throws {
7373
//Given
7474
var called1First = false
7575
var called2First = false
@@ -85,15 +85,15 @@ class NetworkServiceMockTest: XCTestCase {
8585
called2First = true
8686
}
8787
}, onError: { _ in })
88-
networkServiceMock.returnSuccess(with: 0)
89-
networkServiceMock.returnSuccess(with: 0)
88+
try networkServiceMock.returnSuccess(with: 0)
89+
try networkServiceMock.returnSuccess(with: 0)
9090

9191
//Then
9292
XCTAssertTrue(called1First)
9393
XCTAssertFalse(called2First)
9494
}
9595

96-
func testRequestSuccessWithDataChaining() {
96+
func testRequestSuccessWithDataChaining() throws {
9797
//Given
9898
var executionCount1: Int = 0
9999
var executionCount2: Int = 0
@@ -105,15 +105,15 @@ class NetworkServiceMockTest: XCTestCase {
105105
executionCount2 += 1
106106
}, onError: { _ in })
107107
}, onError: { _ in })
108-
networkServiceMock.returnSuccess(with: 0)
109-
networkServiceMock.returnSuccess(with: 0)
108+
try networkServiceMock.returnSuccess(with: 0)
109+
try networkServiceMock.returnSuccess(with: 0)
110110

111111
//Then
112112
XCTAssertEqual(executionCount1, 1)
113113
XCTAssertEqual(executionCount2, 1)
114114
}
115115

116-
func testReturnSuccessWithDataForAllRequests() {
116+
func testReturnSuccessWithDataForAllRequests() throws {
117117
//Given
118118
var executionCount1: Int = 0
119119
var executionCount2: Int = 0
@@ -125,15 +125,15 @@ class NetworkServiceMockTest: XCTestCase {
125125
networkServiceMock.request(resource, onCompletion: { _ in
126126
executionCount2 += 1
127127
}, onError: { _ in })
128-
networkServiceMock.returnSuccess(with: 0)
129-
networkServiceMock.returnSuccess(with: 0)
128+
try networkServiceMock.returnSuccess(with: 0)
129+
try networkServiceMock.returnSuccess(with: 0)
130130

131131
//Then
132132
XCTAssertEqual(executionCount1, 1)
133133
XCTAssertEqual(executionCount2, 1)
134134
}
135135

136-
func testReturnSuccessWithSerializedData() {
136+
func testReturnSuccessWithSerializedData() throws {
137137
//Given
138138
var capturedResult: Int?
139139
var executionCount: Int = 0
@@ -143,14 +143,14 @@ class NetworkServiceMockTest: XCTestCase {
143143
capturedResult = result
144144
executionCount += 1
145145
}, onError: { _ in })
146-
networkServiceMock.returnSuccess(with: 10)
146+
try networkServiceMock.returnSuccess(with: 10)
147147

148148
//Then
149149
XCTAssertEqual(capturedResult, 10)
150150
XCTAssertEqual(executionCount, 1)
151151
}
152152

153-
func testCorrectOrderOfReturnSuccessWithSerializedDataForMultipleRequests() {
153+
func testCorrectOrderOfReturnSuccessWithSerializedDataForMultipleRequests() throws {
154154
//Given
155155
var capturedResult1: Int?
156156
var capturedResult2: Int?
@@ -162,15 +162,15 @@ class NetworkServiceMockTest: XCTestCase {
162162
networkServiceMock.request(resource, onCompletion: { result in
163163
capturedResult2 = result
164164
}, onError: { _ in })
165-
networkServiceMock.returnSuccess(with: 10)
166-
networkServiceMock.returnSuccess(with: 20)
165+
try networkServiceMock.returnSuccess(with: 10)
166+
try networkServiceMock.returnSuccess(with: 20)
167167

168168
//Then
169169
XCTAssertEqual(capturedResult1, 10)
170170
XCTAssertEqual(capturedResult2, 20)
171171
}
172172

173-
func testRequestSuccessWithSerializedDataChaining() {
173+
func testRequestSuccessWithSerializedDataChaining() throws {
174174
//Given
175175
var executionCount1: Int = 0
176176
var executionCount2: Int = 0
@@ -182,15 +182,15 @@ class NetworkServiceMockTest: XCTestCase {
182182
executionCount2 += 1
183183
}, onError: { _ in })
184184
}, onError: { _ in })
185-
networkServiceMock.returnSuccess(with: 10)
186-
networkServiceMock.returnSuccess(with: 20)
185+
try networkServiceMock.returnSuccess(with: 10)
186+
try networkServiceMock.returnSuccess(with: 20)
187187

188188
//Then
189189
XCTAssertEqual(executionCount1, 1)
190190
XCTAssertEqual(executionCount2, 1)
191191
}
192192

193-
func testReturnSuccessWithSerializedDataForAllRequests() {
193+
func testReturnSuccessWithSerializedDataForAllRequests() throws {
194194
//Given
195195
var executionCount1: Int = 0
196196
var executionCount2: Int = 0
@@ -202,15 +202,15 @@ class NetworkServiceMockTest: XCTestCase {
202202
networkServiceMock.request(resource, onCompletion: { _ in
203203
executionCount2 += 1
204204
}, onError: { _ in })
205-
networkServiceMock.returnSuccess(with: 10)
206-
networkServiceMock.returnSuccess(with: 10)
205+
try networkServiceMock.returnSuccess(with: 10)
206+
try networkServiceMock.returnSuccess(with: 10)
207207

208208
//Then
209209
XCTAssertEqual(executionCount1, 1)
210210
XCTAssertEqual(executionCount2, 1)
211211
}
212212

213-
func testReturnError() {
213+
func testReturnError() throws {
214214
//Given
215215
var capturedError: NetworkError?
216216
var executionCount: Int = 0
@@ -220,7 +220,7 @@ class NetworkServiceMockTest: XCTestCase {
220220
capturedError = error
221221
executionCount += 1
222222
})
223-
networkServiceMock.returnError(with: .unknownError)
223+
try networkServiceMock.returnError(with: .unknownError)
224224

225225
//Then
226226
if let error = capturedError, case .unknownError = error {
@@ -231,7 +231,7 @@ class NetworkServiceMockTest: XCTestCase {
231231
XCTAssertEqual(executionCount, 1)
232232
}
233233

234-
func testCorrectOrderOfReturnErrorForMultipleRequests() {
234+
func testCorrectOrderOfReturnErrorForMultipleRequests() throws {
235235
//Given
236236
var capturedError1: NetworkError?
237237
var capturedError2: NetworkError?
@@ -243,8 +243,8 @@ class NetworkServiceMockTest: XCTestCase {
243243
networkServiceMock.request(resource, onCompletion: { _ in }, onError: { error in
244244
capturedError2 = error
245245
})
246-
networkServiceMock.returnError(with: .unknownError)
247-
networkServiceMock.returnError(with: .cancelled)
246+
try networkServiceMock.returnError(with: .unknownError)
247+
try networkServiceMock.returnError(with: .cancelled)
248248

249249
//Then
250250
if case .unknownError? = capturedError1, case .cancelled? = capturedError2 {
@@ -254,7 +254,7 @@ class NetworkServiceMockTest: XCTestCase {
254254
}
255255
}
256256

257-
func testRequestErrorChaining() {
257+
func testRequestErrorChaining() throws {
258258
//Given
259259
var executionCount1: Int = 0
260260
var executionCount2: Int = 0
@@ -267,15 +267,15 @@ class NetworkServiceMockTest: XCTestCase {
267267
})
268268
})
269269

270-
networkServiceMock.returnError(with: .unknownError)
271-
networkServiceMock.returnError(with: .unknownError)
270+
try networkServiceMock.returnError(with: .unknownError)
271+
try networkServiceMock.returnError(with: .unknownError)
272272

273273
//Then
274274
XCTAssertEqual(executionCount1, 1)
275275
XCTAssertEqual(executionCount2, 1)
276276
}
277277

278-
func testReturnErrorsForAllRequests() {
278+
func testReturnErrorsForAllRequests() throws {
279279
//Given
280280
var executionCount1: Int = 0
281281
var executionCount2: Int = 0
@@ -287,12 +287,42 @@ class NetworkServiceMockTest: XCTestCase {
287287
networkServiceMock.request(resource, onCompletion: { _ in }, onError: { _ in
288288
executionCount2 += 1
289289
})
290-
networkServiceMock.returnError(with: .unknownError)
291-
networkServiceMock.returnError(with: .unknownError)
290+
try networkServiceMock.returnError(with: .unknownError)
291+
try networkServiceMock.returnError(with: .unknownError)
292292

293293
//Then
294294
XCTAssertEqual(executionCount1, 1)
295295
XCTAssertEqual(executionCount2, 1)
296296
}
297297

298+
func testReturnSuccessMismatchType() {
299+
//When
300+
networkServiceMock.request(resource, onCompletion: { _ in }, onError: { _ in })
301+
302+
//Then
303+
XCTAssertThrowsError(try networkServiceMock.returnSuccess(with: "Mismatch Type"))
304+
}
305+
306+
func testReturnSuccessMissingRequest() {
307+
//Then
308+
XCTAssertThrowsError(try networkServiceMock.returnSuccess(with: 1))
309+
}
310+
311+
func testReturnErrorMissingRequest() {
312+
//Then
313+
XCTAssertThrowsError(try networkServiceMock.returnError(with: .unknownError))
314+
}
315+
316+
func testPendingRequestCountEmpty() {
317+
XCTAssertEqual(networkServiceMock.pendingRequestCount, 0)
318+
}
319+
320+
func testPendingRequestCountNotEmpty() {
321+
//When
322+
networkServiceMock.request(resource, onCompletion: { _ in }, onError: { _ in })
323+
324+
//Then
325+
XCTAssertEqual(networkServiceMock.pendingRequestCount, 1)
326+
}
327+
298328
}

0 commit comments

Comments
 (0)