You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift:如何在测试目标中为含required init的类扩展Decodable

在测试目标中为含required初始化器的类扩展Decodable的解决方案

问题本质

非final类在extension中实现协议的初始化器要求时,Swift强制要求将该初始化器标记为required,但required初始化器只能定义在类的主定义中,无法放在extension内。而你希望仅在测试场景中实现Decodable,不愿修改主目标的类定义,因此需要规避这个限制。


方案1:创建Final子类(推荐)

在测试目标中定义一个继承自DemoClass的final子类,让子类实现Decodable。由于final类不会被继承,无需将init(from:)标记为required,完美适配测试需求:

import XCTest
@testable import YourMainModule // 替换为你的主模块名

final class DecodableDemoClass: DemoClass, Decodable {
    init(from decoder: Decoder) throws {
        // 先调用父类的required初始化器完成基础初始化
        try super.init()
        
        // 编写解码逻辑,示例如下:
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 假设DemoClass有`name`属性,解码并赋值
        // self.name = try container.decode(String.self, forKey: .name)
    }
    
    // 自定义CodingKeys(根据你的JSON结构调整)
    enum CodingKeys: String, CodingKey {
        // case name
    }
}

测试时直接使用DecodableDemoClass解码JSON,得到的实例可直接作为DemoClassProtocol类型使用,完全不影响主目标代码。


方案2:使用包装结构体

若不想创建子类,可在测试目标中定义一个包装结构体,实现Decodable后再转换成DemoClass实例:

import XCTest
@testable import YourMainModule

struct DemoClassWrapper: Decodable {
    let demoInstance: DemoClass
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 初始化DemoClass实例
        demoInstance = DemoClass()
        // 解码并设置实例属性
        // demoInstance.name = try container.decode(String.self, forKey: .name)
    }
    
    enum CodingKeys: String, CodingKey {
        // case name
    }
}

使用时先解码得到DemoClassWrapper,再通过demoInstance属性获取DemoClass对象即可。


内容的提问来源于stack exchange,提问作者PlankTon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 11:25:30