Skip to content

Commit b9c6e99

Browse files
authored
added single path setup functions.
XCTest calls setupWithError and tearDownWithError before each test method. This can be used to setup the sql client for each test. This centralises the test setup and cleanup. Ensuring that there is no race condition from a defer task, as well as shortening the logic for each test. Local clients have been constructed for testing connections and double connects. As this would not be compatible with the more global approach.
1 parent 1ac7f10 commit b9c6e99

1 file changed

Lines changed: 38 additions & 42 deletions

File tree

Tests/SQLClientSwiftTests/SQLClientSwiftTests.swift

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,98 +13,107 @@ final class SQLClientSwiftTests: XCTestCase {
1313
private var password: String { env("PASSWORD") }
1414
private var database: String { env("DATABASE") }
1515
private var canConnect: Bool { !host.isEmpty && !username.isEmpty && !password.isEmpty }
16+
private var client: SQLClient! // global client
1617

1718
private func makeClient() async throws -> SQLClient {
19+
let c = SQLClient()
20+
try await c.connect(server: host, username: username, password: password,
21+
database: database.isEmpty ? nil : database)
22+
return c
23+
}
24+
25+
/// Called before each XCTest method is run. Able to throw errors on setup.
26+
/// Centralises boilerplate setup making
27+
override func setupWithError() throws {
28+
try await super.setupWithError()
1829
guard canConnect else {
1930
throw XCTSkip("Set HOST, USERNAME, PASSWORD environment variables to run tests.")
2031
}
21-
let client = SQLClient()
22-
try await client.connect(server: host, username: username, password: password,
23-
database: database.isEmpty ? nil : database)
24-
return client
32+
client = try await makeClient()
2533
}
2634

35+
/// Called after each XCTest method is run. Able to throw errors on cleanup.
36+
/// Ensures cleanup from each test is completed after the test is run. Before
37+
/// the next test is run.
38+
override func tearDownWithError() throws {
39+
try await client.disconnect()
40+
try await super.tearDownWithError()
41+
}
42+
43+
2744
func testConnect() async throws {
28-
let client = try await makeClient()
29-
let connected = await client.isConnected
45+
// Use a local client, as the global client is already connected
46+
let localClient = SQLClient()
47+
try await localClient.connect(server: host, username: username, password: password,
48+
database: database.isEmpty ? nil : database)
49+
50+
let connected = await localClient.isConnected
3051
XCTAssertTrue(connected)
31-
await client.disconnect()
32-
let isConnected = await client.isConnected
52+
53+
await localClient.disconnect()
54+
let isConnected = await localClient.isConnected
3355
XCTAssertFalse(isConnected)
3456
}
3557

3658
func testDoubleConnectThrows() async throws {
37-
let client = try await makeClient()
38-
defer { Task { await client.disconnect() } }
59+
// Use a local client as the global client is already connected
60+
let localClient = SQLClient()
61+
try await localClient.connect(server: host, username: username, password: password,
62+
database: database.isEmpty ? nil : database)
63+
// Defer is used here as race condition on cleanup is inconsequential
64+
defer { Task { await localClient.disconnect() } }
65+
3966
do {
40-
try await client.connect(server: host, username: username, password: password)
67+
try await localClient.connect(server: host, username: username, password: password)
4168
XCTFail("Expected alreadyConnected")
4269
} catch SQLClientError.alreadyConnected { }
4370
}
4471

4572
func testSelectScalar() async throws {
46-
let client = try await makeClient()
47-
defer { Task { await client.disconnect() } }
4873
let rows = try await client.query("SELECT 42 AS Answer")
4974
XCTAssertEqual(rows.count, 1)
5075
XCTAssertEqual(rows[0].int("Answer"), 42)
5176
}
5277

5378
func testSelectNull() async throws {
54-
let client = try await makeClient()
55-
defer { Task { await client.disconnect() } }
5679
let rows = try await client.query("SELECT NULL AS Val")
5780
XCTAssertTrue(rows[0].isNull("Val"))
5881
}
5982

6083
func testSelectString() async throws {
61-
let client = try await makeClient()
62-
defer { Task { await client.disconnect() } }
6384
let rows = try await client.query("SELECT 'Hello' AS Msg")
6485
XCTAssertEqual(rows[0].string("Msg"), "Hello")
6586
}
6687

6788
func testSelectFloat() async throws {
68-
let client = try await makeClient()
69-
defer { Task { await client.disconnect() } }
7089
let rows = try await client.query("SELECT CAST(3.14 AS FLOAT) AS Pi")
7190
XCTAssertEqual(rows[0].double("Pi") ?? 0, 3.14, accuracy: 0.001)
7291
}
7392

7493
func testSelectBit() async throws {
75-
let client = try await makeClient()
76-
defer { Task { await client.disconnect() } }
7794
let rows = try await client.query("SELECT CAST(1 AS BIT) AS Flag")
7895
XCTAssertEqual(rows[0].bool("Flag"), true)
7996
}
8097

8198
func testSelectDateTime() async throws {
82-
let client = try await makeClient()
83-
defer { Task { await client.disconnect() } }
8499
let rows = try await client.query("SELECT GETDATE() AS Now")
85100
XCTAssertNotNil(rows[0].date("Now"))
86101
}
87102

88103
func testMultipleRows() async throws {
89-
let client = try await makeClient()
90-
defer { Task { await client.disconnect() } }
91104
let rows = try await client.query("SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3")
92105
XCTAssertEqual(rows.count, 3)
93106
XCTAssertEqual(rows.map { $0.int("n") }, [1, 2, 3])
94107
}
95108

96109
func testMultipleResultSets() async throws {
97-
let client = try await makeClient()
98-
defer { Task { await client.disconnect() } }
99110
let result = try await client.execute("SELECT 1 AS A; SELECT 2 AS B;")
100111
XCTAssertEqual(result.tables.count, 2)
101112
XCTAssertEqual(result.tables[0][0].int("A"), 1)
102113
XCTAssertEqual(result.tables[1][0].int("B"), 2)
103114
}
104115

105116
func testRowsAffected() async throws {
106-
let client = try await makeClient()
107-
defer { Task { await client.disconnect() } }
108117
try await client.run("""
109118
IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T;
110119
CREATE TABLE #T (id INT);
@@ -116,21 +125,16 @@ final class SQLClientSwiftTests: XCTestCase {
116125
}
117126

118127
func testParameterisedQuery() async throws {
119-
let client = try await makeClient()
120-
defer { Task { await client.disconnect() } }
121128
let rows = try await client.execute("SELECT ? AS Name", parameters: ["O'Brien"])
122129
XCTAssertEqual(rows.rows[0].string("Name"), "O'Brien")
123130
}
124131

125132
func testNullParameter() async throws {
126-
let client = try await makeClient()
127-
defer { Task { await client.disconnect() } }
128133
let rows = try await client.execute("SELECT ? AS Val", parameters: [nil])
129134
XCTAssertTrue(rows.rows[0].isNull("Val"))
130135
}
131136

132137
func testParameterCountMismatch() async throws {
133-
let client = try await makeClient()
134138
defer { Task { await client.disconnect() } }
135139
do {
136140
_ = try await client.execute("SELECT ? AS A", parameters: [1, 2])
@@ -139,35 +143,27 @@ final class SQLClientSwiftTests: XCTestCase {
139143
}
140144

141145
func testDecodableStruct() async throws {
142-
let client = try await makeClient()
143-
defer { Task { await client.disconnect() } }
144146
struct Point: Decodable { let x: Int; let y: Int }
145147
let points: [Point] = try await client.query("SELECT 10 AS x, 20 AS y")
146148
XCTAssertEqual(points[0].x, 10)
147149
XCTAssertEqual(points[0].y, 20)
148150
}
149151

150152
func testDecodableSnakeCase() async throws {
151-
let client = try await makeClient()
152-
defer { Task { await client.disconnect() } }
153153
struct Item: Decodable { let itemId: Int; let itemName: String }
154154
let items: [Item] = try await client.query("SELECT 7 AS item_id, 'Widget' AS item_name")
155155
XCTAssertEqual(items[0].itemId, 7)
156156
XCTAssertEqual(items[0].itemName, "Widget")
157157
}
158158

159159
func testBadSQLThrows() async throws {
160-
let client = try await makeClient()
161-
defer { Task { await client.disconnect() } }
162160
do {
163161
_ = try await client.execute("THIS IS NOT VALID SQL")
164162
XCTFail("Expected executionFailed")
165163
} catch SQLClientError.executionFailed { }
166164
}
167165

168166
func testEmptySQLThrows() async throws {
169-
let client = try await makeClient()
170-
defer { Task { await client.disconnect() } }
171167
do {
172168
_ = try await client.execute(" ")
173169
XCTFail("Expected noCommandText")

0 commit comments

Comments
 (0)