Как устранить ошибку в модульном тестировании, когда у нас есть Сравнение дат в Codable - PullRequest
0 голосов
/ 09 февраля 2020

Я пытался использовать пользовательскую стратегию даты в json декодировании с использованием Codable, как описано в { ссылка }. Вот упрощенный код реализации:

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))
    }
}

Однако, когда дело доходит до модульного тестирования, оно терпит неудачу, хотя сообщение об ошибке показывает равное значение, используемое description методом даты:

    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]"
    }

Есть ли у вас какие-либо идеи о том, в чем заключается проблема и как мы можем ее решить?

Кстати, фактический декодируемый объект - это следующий, где publishedAt имеет тип даты:

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 Ответ

0 голосов
/ 09 февраля 2020

То, что вы тестируете, - это преобразование даты / строки, поэтому нет необходимости включать JSON кодирование и декодирование в это. Начните с фиксированной даты в строковой форме, преобразуйте ее в дату и обратно и проверьте конечный результат по сравнению с фиксированной датой

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!)

Обратите внимание, что это было написано на игровой площадке, а не как модульный тест

...