使用 SingleValueDecodingContainer 进行单元测试与 Decodable 的一致性

vru*_*erg 5 unit-testing swift codable decodable

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

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

这种类型的重点是如果我有如下所示的 JSON:

{
    "identifier": "abc123",
    // more properties ...
}
Run Code Online (Sandbox Code Playgroud)

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

我想做的是这样的:

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

但显然这不起作用,因为"1"不是有效的 JSON。

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

mel*_*aka 6

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

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

我们的测试将如下所示;

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)
    }
}
Run Code Online (Sandbox Code Playgroud)


vru*_*erg 1

我放弃了在不创建包装类型的情况下完成此任务的尝试,因为假设很难解码一开始就不是有效 JSON 的字符串('1'在我的示例中)。

\n\n

所以,我想,答案是:只需创建一个包装类型。\xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf

\n