上一篇講 Error handling 是指 Error 在 URLSession 時發生,可能是 4 開頭或 5 開頭的 Error。但有另一種可能,後端 HTTPURLResponse 的 status code 是回 2 開頭成功,但 json response 的格式和程式不一樣,問題可能在前端可能在後端,也可能是規格變更後,有一端沒有 sync 到。這會讓 JSON decode 解不開,今天的程式,是測 DecodingError
step1: 在 APIClientTest 中加上 Decode 的這一段
func testStockClosePriceListDecodeError() async throws {
let url = try XCTUnwrap(URL(string: "foo"))
let urlSessionMock = URLSessionProtocolMock()
urlSessionMock.dataForDelegateReturnValue = (
try JSONEncoder().encode("dummyObject"),
HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: nil)!
)
sut.session = urlSessionMock
do {
_ = try await sut.getStockClosPriceList()
XCTFail("this test should not get here")
} catch {
XCTAssertTrue(error is Swift.DecodingError)
}
}
跑完測試後因為都 pass,如果想確認這一道測試,可以暫時把 APIClient 改成下面這樣,確認測試會 failed 後,再改回來
/// APIClient.swift
/// 確認 test 可以 failed 時的改法
func getStockClosPriceList() async throws -> [StockDailyInfoElement] {
guard let url = URL(string: "https://openapi.twse.com.tw/v1/exchangeReport/STOCK_DAY_AVG_ALL") else {
return []
}
let request = URLRequest(url: url)
let (data, _) = try await session.data(for: request, delegate: nil)
let stocks = try? JSONDecoder().decode([StockDailyInfoElement].self, from: data)
return stocks ?? []
}
/// APIClient.swift
/// 確認後將 APIClient 改回來
func getStockClosPriceList() async throws -> [StockDailyInfoElement] {
guard let url = URL(string: "https://openapi.twse.com.tw/v1/exchangeReport/STOCK_DAY_AVG_ALL") else {
return []
}
let request = URLRequest(url: url)
let (data, _) = try await session.data(for: request, delegate: nil)
let stocks = try JSONDecoder().decode([StockDailyInfoElement].self, from: data)
return stocks
}