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
相关产品推荐
相关产品推荐

