问题
I tried to use custom date strategy in json decoding using Codable
as describe in https://stackoverflow.com/a/28016692/3477974 . Here is the simplified implementation code:
public extension Formatter {
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
}
public extension Date {
var iso8601: String {
return Formatter.iso8601.string(from: self)
}
}
public extension JSONDecoder.DateDecodingStrategy {
static let iso8601withFractionalSeconds = custom {
let container = try $0.singleValueContainer()
let string = try container.decode(String.self)
guard let date = Formatter.iso8601.date(from: string) else {
throw DecodingError.dataCorruptedError(in: container,
debugDescription: "Invalid date: " + string)
}
return date
}
}
public extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601.string(from: $0))
}
}
However, when it comes to unit testing it fails although the error message shows equal value used by description
method of date:
func test_jsonCodable_iso8601() {
let dates = [Date()] // ["Feb 9, 2020 at 12:55:24 PM"]
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 9, 2020 at 12:55:24 PM"]
XCTAssertEqual(dates, decodedDates)
// fails with error message: [2020-02-09 12:55:24 +0000]") is not equal to ("[2020-02-09 12:55:24 +0000]"
}
Do you have any idea what is the issue and how we can resolve it?
By the way, the actual decodable object is the following one where publishedAt
is of type date:
public struct NewsItem: Equatable {
public let id: UUID
public let author: String
public let title: String
public let description: String
public let urlToImage: URL?
public let publishedAt: Date
public let content: String
public init(id: UUID,
author: String,
title: String,
description: String,
urlToImage: URL?,
publishedAt: Date,
content: String) {
self.id = id
self.author = author
self.title = title
self.description = description
self.urlToImage = urlToImage
self.publishedAt = publishedAt
self.content = content
}
}
extension NewsItem: Decodable {}
回答1:
What you are testing is the date/string conversion so there is no need to involve JSON encoding and decoding into this. Start with a fixed date in string form, convert it to date and back and check the end result vs the fixed date
let input = "2020-02-02T19:10:23.123Z"
let formatter = DateFormatter.iso8601
let date = formatter.date(from: input)
let output = date?.iso8601
print(date != nil && input == output!)
Note that this was written in a playground and not as a unit test
来源:https://stackoverflow.com/questions/60136982/how-to-resolve-error-in-unit-testing-when-we-have-date-comparison-in-codable