-
Notifications
You must be signed in to change notification settings - Fork 491
Expand file tree
/
Copy pathURLSessionHTTPClientTests.swift
More file actions
137 lines (104 loc) · 4.99 KB
/
URLSessionHTTPClientTests.swift
File metadata and controls
137 lines (104 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//
// Copyright © Essential Developer. All rights reserved.
//
import XCTest
import EssentialFeed
@MainActor
class URLSessionHTTPClientTests: XCTestCase {
override func tearDown() {
super.tearDown()
URLProtocolStub.removeStub()
}
func test_getFromURL_performsGETRequestWithURL() async throws {
let url = anyURL()
let exp = expectation(description: "Wait for request")
URLProtocolStub.observeRequests { request in
XCTAssertEqual(request.url, url)
XCTAssertEqual(request.httpMethod, "GET")
exp.fulfill()
}
_ = try await makeSUT().get(from: url)
await fulfillment(of: [exp], timeout: 1.0)
}
func test_cancelGetFromURLTask_cancelsURLRequest() async {
var task: Task<(Data, HTTPURLResponse), Error>?
URLProtocolStub.onStartLoading { task?.cancel() }
let receivedError = await resultErrorFor(taskHandler: { task = $0 }) as NSError?
XCTAssertEqual(receivedError?.code, URLError.cancelled.rawValue)
}
func test_getFromURL_failsOnRequestError() async {
let requestError = anyNSError()
let receivedError = await resultErrorFor((data: nil, response: nil, error: requestError))
XCTAssertNotNil(receivedError)
}
func test_getFromURL_failsOnAllInvalidRepresentationCases() async {
assertNotNil(await resultErrorFor((data: nil, response: nonHTTPURLResponse(), error: nil)))
assertNotNil(await resultErrorFor((data: anyData(), response: nil, error: anyNSError())))
assertNotNil(await resultErrorFor((data: nil, response: nonHTTPURLResponse(), error: anyNSError())))
assertNotNil(await resultErrorFor((data: nil, response: anyHTTPURLResponse(), error: anyNSError())))
assertNotNil(await resultErrorFor((data: anyData(), response: nonHTTPURLResponse(), error: anyNSError())))
assertNotNil(await resultErrorFor((data: anyData(), response: anyHTTPURLResponse(), error: anyNSError())))
assertNotNil(await resultErrorFor((data: anyData(), response: nonHTTPURLResponse(), error: nil)))
}
func test_getFromURL_succeedsOnHTTPURLResponseWithData() async {
let data = anyData()
let response = anyHTTPURLResponse()
let receivedValues = await resultValuesFor((data: data, response: response, error: nil))
XCTAssertEqual(receivedValues?.data, data)
XCTAssertEqual(receivedValues?.response.url, response.url)
XCTAssertEqual(receivedValues?.response.statusCode, response.statusCode)
}
func test_getFromURL_succeedsWithEmptyDataOnHTTPURLResponseWithNilData() async {
let response = anyHTTPURLResponse()
let receivedValues = await resultValuesFor((data: nil, response: response, error: nil))
let emptyData = Data()
XCTAssertEqual(receivedValues?.data, emptyData)
XCTAssertEqual(receivedValues?.response.url, response.url)
XCTAssertEqual(receivedValues?.response.statusCode, response.statusCode)
}
// MARK: - Helpers
private func makeSUT(file: StaticString = #filePath, line: UInt = #line) -> HTTPClient {
let configuration = URLSessionConfiguration.ephemeral
configuration.protocolClasses = [URLProtocolStub.self]
let session = URLSession(configuration: configuration)
let sut = URLSessionHTTPClient(session: session)
trackForMemoryLeaks(sut, file: file, line: line)
return sut
}
private func resultValuesFor(_ values: (data: Data?, response: URLResponse?, error: Error?), file: StaticString = #filePath, line: UInt = #line) async -> (data: Data, response: HTTPURLResponse)? {
do {
let result = try await resultFor(values, file: file, line: line)
return result
} catch {
XCTFail("Expected success, got \(error) instead", file: file, line: line)
return nil
}
}
private func resultErrorFor(_ values: (data: Data?, response: URLResponse?, error: Error?)? = nil, taskHandler: (Task<(Data, HTTPURLResponse), Error>) -> Void = { _ in }, file: StaticString = #filePath, line: UInt = #line) async -> Error? {
do {
let result = try await resultFor(values, taskHandler: taskHandler, file: file, line: line)
XCTFail("Expected failure, got \(result) instead", file: file, line: line)
return nil
} catch {
return error
}
}
private func resultFor(_ values: (data: Data?, response: URLResponse?, error: Error?)?, taskHandler: (Task<(Data, HTTPURLResponse), Error>) -> Void = { _ in }, file: StaticString = #filePath, line: UInt = #line) async throws -> (Data, HTTPURLResponse) {
values.map { URLProtocolStub.stub(data: $0, response: $1, error: $2) }
let sut = makeSUT(file: file, line: line)
let task = Task {
return try await sut.get(from: anyURL())
}
taskHandler(task)
return try await task.value
}
private func anyHTTPURLResponse() -> HTTPURLResponse {
return HTTPURLResponse(url: anyURL(), statusCode: 200, httpVersion: nil, headerFields: nil)!
}
private func nonHTTPURLResponse() -> URLResponse {
return URLResponse(url: anyURL(), mimeType: nil, expectedContentLength: 0, textEncodingName: nil)
}
}
private func assertNotNil(_ value: Any?, _ message: @autoclosure () -> String = "", file: StaticString = #filePath, line: UInt = #line) {
XCTAssertNotNil(value, message(), file: file, line: line)
}