如何在KMM中获取iOS TestRunner或TestBundle的随机文件路径?
在KMM iOS端UI测试中读取测试Bundle文件的正确方法
问题背景
在Xcode中进行UI测试时,可通过以下代码读取UITest Bundle下的文件:
func testReadFile() throws { // 获取UI测试目标的Bundle let testBundle = Bundle(for: XCTestBase.self) // 查找当前测试运行器下的文件 if let filePath = testBundle.url(forResource: "good", withExtension: "txt") { print(filePath) } }
通过LLDB的po命令可以看到,文件路径指向运行时生成的随机路径,关联到iosAppUITests-Runner实例:
(lldb) po testBundle.url(forResource: "good", withExtension: "txt") ▿ Optional<URL> ▿ some : file:///Users/haibozhou/Library/Developer/CoreSimulator/Devices/EFF818A9-6670-4635-9618-DEBFB2C15156/data/Containers/Bundle/Application/DA9E0623-D0DF-414C-A831-5654BBB64AF8/iosAppUITests-Runner.app/PlugIns/iosAppUITests.xctest/good.txt - _url : file:///Users/haibozhou/Library/Developer/CoreSimulator/Devices/EFF818A9-6670-4635-9618-DEBFB2C15156/data/Containers/Bundle/Application/DA9E0623-D0DF-414C-A831-5654BBB64AF8/iosAppUITests-Runner.app/PlugIns/iosAppUITests.xctest/good.txt
但在KMM项目的iOS Kotlin代码中尝试实现相同功能时遇到问题:
- 无法解析测试类
XCTestBase,推测是该类未暴露给KMM项目:val testBundle = NSBundle.bundleForClass(XCTestBase) - 尝试使用相对路径读取也失败:
actual fun readFile(path: String): String { val string = NSString.stringWithContentsOfFile( "../iosAppUITests-Runner.app/PlugIns/iosAppUITests.xctest/good.txt", NSUTF8StringEncoding, null) ?: return "File not found!" // 省略其他代码... return string }
请问在KMM的iOS Kotlin代码中,获取iOS测试运行器文件路径的正确方法是什么?
解决方案
在KMM的iOS端测试代码中,可通过以下两种可靠方式获取测试Bundle并读取文件:
方法1:通过当前测试类获取Bundle
如果你的KMM测试类继承自XCTestCase,直接用当前类的javaClass即可定位到对应测试Bundle:
actual fun readFile(fileName: String, fileExtension: String): String { // 获取当前测试类对应的Bundle val testBundle = NSBundle.bundleForClass(this.javaClass) // 查找目标文件的URL val fileUrl = testBundle.URLForResource(fileName, withExtension = fileExtension) ?: return "File not found!" // 读取文件内容 return NSString.stringWithContentsOfURL(fileUrl, NSUTF8StringEncoding, null) ?: "Failed to read file content!" }
方法2:通过Bundle Identifier获取测试Bundle
如果无法通过类对象获取Bundle,可以直接使用测试Target的Bundle Identifier定位:
actual fun readFile(path: String): String { // 替换为你XCTest Target的Bundle Identifier val testBundle = NSBundle.bundleWithIdentifier("com.yourcompany.iosAppUITests") ?: return "Test bundle not found!" val filePath = testBundle.pathForResource("good", ofType = "txt") ?: return "File not found!" return NSString.stringWithContentsOfFile(filePath, NSUTF8StringEncoding, null) ?: "Failed to read file!" }
关键注意事项
- 确保测试文件已添加到KMM的iOS测试Target中:在Xcode里找到目标文件,勾选对应的测试Target的"Target Membership";
- 禁止硬编码相对路径:测试运行器的路径是随机生成的,硬编码路径会导致跨环境失效,必须用
URLForResource或pathForResource方法动态查找; - 方法2中的Bundle Identifier必须与Xcode测试Target的配置完全一致。
内容的提问来源于stack exchange,提问作者Zhou Haibo
相关产品推荐
相关产品推荐

