使用 SingleValueDecodingContainer 对 Decodable 的单元测试一致性

Unit testing conformance to Decodable using a SingleValueDecodingContainer

所以,我有一个看起来像这样的类型:

struct Identifier {
    let string: String
}

extension Identifier: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        string = try container.decode(String.self)
    }
}

这种类型的要点是如果我有 JSON 看起来像这样:

{
    "identifier": "abc123",
    // more properties ...
}

... 它会自动序列化为正确的类型,无需太多努力。但是,我无法在不创建包装类型的情况下对 Decodable 的一致性进行单元测试。

我想做的是这样的:

func testDecodableInit() {
    let identifier = try! JSONDecoder().decode(Identifier.self, from: "1".data(using: .utf8)!)
    XCTAssertEqual(identifier.string, "1")
}

但显然这行不通,因为 "1" 无效 JSON.

是否可以在不创建包装类型并将数据更改为有效 JSON 的情况下编写符合 Decodable 的单元测试?

我放弃了尝试在不创建包装类型的情况下完成此操作,因为假设很难解码无效的字符串 JSON 开头('1' 在我的示例中).

所以,我想答案是:只需创建一个包装类型。 ¯\_(ツ)_/¯

如果有人想知道如何使用包装类型创建测试。看起来像这样;

struct Identifier {
    let string: String
}

extension Identifier: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        string = try container.decode(String.self)
    }
}

我们的测试将如下所示;

class IdentifierTests: XCTestCase {

    func testStringValueDecodedSuccessfully() throws {
        let decoder = JSONDecoder()
        let data = Data("{\"value\": \"identifier-string\"}".utf8)
        let container = try decoder.decode(Wrapper1.self, from: data)
        XCTAssertEqual(container.identifierValue.string, "identifier-string")
    }
}

private struct Wrapper: Decodable {

    let identifierValue: Identifier

    enum CodingKeys: String, CodingKey {
        case value
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        identifierValue = try container.decode(Identifier.self, forKey: .value)
    }
}