@testable import无法导入项目全部文件的测试访问问题求助
我之前也碰到过一模一样的问题,其实核心是@testable import的工作机制和单个外部文件的Target Membership配置没匹配上,咱们一步步拆解:
1. 先搞懂@testable import的本质
@testable import 主Target名的作用是让单元测试Target能访问主Target里标记为internal的成员,但它有个关键前提:你要测试的文件必须属于主Target的编译范围,同时单元测试Target和主Target的关联是正确的(也就是单元测试的Host Application设置为主Target)。
但这里的特殊情况是:你添加的是外部框架的单个文件,不是完整引入框架,这就触发了Target Membership的配置矛盾。
2. 为什么会出现“能间接调用但没法直接测试”的矛盾?
- 当你把外部文件拖进项目,默认只会勾选主Target的Membership,单元测试Target没被勾选。这时候主Target编译时会包含这个文件,所以单元测试通过
@testable import主Target后,能调用主Target里那些使用了这个外部文件的函数——相当于“借道”主Target的编译结果来间接访问。 - 但单元测试Target本身并没有把这个外部文件纳入自己的编译范围,所以编译器根本找不到这个文件的定义(就是你提到的
no-such...类错误,比如no such type或者use of unresolved identifier),自然没法直接测试这个文件里的函数/类型。
3. 可行的解决办法
办法一:给外部文件勾选单元测试Target的Membership
找到这个外部文件,在右侧Inspector面板的Target Membership里,除了主Target,再勾选你的单元测试Target。
注意:如果这个文件依赖主Target里的其他代码,要确保单元测试Target的
Build Phases -> Compile Sources里,这个文件的编译顺序在它依赖的文件之后,不然会出现编译错误。
办法二:改用正规的依赖管理方式引入框架
这是更推荐的做法:不要直接拖单个文件,而是用Swift Package Manager、CocoaPods或者Carthage把整个外部框架作为依赖引入。
这样单元测试可以直接import 外部框架名,不需要依赖主Target的@testable,而且能直接测试框架里的所有内容,也避免了单个文件带来的Target配置混乱。
办法三:把单个文件封装为主Target的子模块
如果必须用单个文件,可以把它放到主Target的一个子模块(比如新建一个Group,标记为子模块),然后在单元测试里同时@testable import 主Target和import 子模块名。不过这种方式比较繁琐,不如直接用依赖管理省心。
内容的提问来源于stack exchange,提问作者SwiftyJD

