Swift Package引用应用Main.storyboard全量单元测试报错问题
问题根源
- 单独运行单个测试用例时,Xcode的测试运行上下文会直接绑定你的应用作为唯一宿主,此时调用
Bundle.main(你传nil给UIStoryboard时默认用的就是Bundle.main)指向的是应用的主bundle,里面包含Main.storyboard,因此加载正常。 - 全量运行单元测试时,Xcode为了提升运行效率通常会默认开启并行测试,或者在多个测试target切换执行时,会将XCTest运行时的代理bundle(也就是报错信息里的
Xcode/Agents对应的bundle)临时设置为Bundle.main,此时你再传nil查找storyboard就会找错bundle,自然找不到你应用里的Main.storyboard。
修复方案
短期快速修复
不要在加载storyboard时传nil硬编码使用主bundle,改为显式指定你应用的bundle:
- 给
decorateGameOverScene方法新增可注入的bundle参数,默认值留空兼容原有业务逻辑:
func decorateGameOverScene(from model: GameEndData, bundle: Bundle = .main) { // 原有逻辑... let storyboard = UIStoryboard(name: "Main", bundle: bundle) // 原有逻辑... }
- 测试时主动传入应用的bundle即可,不用依赖主bundle的上下文:
// 用你应用中任意一个类来获取应用对应的bundle let appBundle = Bundle(for: AppDelegate.self) decorateGameOverScene(from: 测试用的model, bundle: appBundle)
长期规范方案
如果你的Swift Package本身需要用到storyboard资源,直接把资源迁入包内统一管理:
- 在Package.swift的对应target配置中添加资源声明:
.target( name: "你的Package模块名", resources: [ .process("Resources/Main.storyboard") ] )
- 加载storyboard时使用Swift Package专属的
Bundle.module来访问包内资源,完全避免bundle查找错误:
let storyboard = UIStoryboard(name: "Main", bundle: .module)
单元测试优化方案
单元测试不需要依赖真实的storyboard加载,你可以把视图控制器初始化的逻辑抽成协议注入,测试时直接返回Mock的视图控制器即可,完全规避资源加载的问题。
内容的提问来源于stack exchange,提问作者Mercutio
相关产品推荐
相关产品推荐

