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

时间:2018-05-08 16:03:04

标签: swift unit-testing 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)
    }
}

这种类型的观点是,如果我有这样的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编写此符合性的单元测试?

2 个答案:

答案 0 :(得分: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)
    }
}

答案 1 :(得分:0)

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

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