如何让XCUITest应用访问照片库并获取添加的图片上传服务器?
解决XCUITest应用自身访问照片库并上传图片的问题
我来帮你搞定这个问题!因为XCUITest的测试应用和你的被测试应用(SUT)是完全独立的沙盒环境,所以你得单独给测试应用配置权限、处理访问逻辑,而不是依赖SUT的配置。下面一步步来:
一、先给XCUITest测试Target配置照片库权限
测试应用要访问照片库,得先在它的Info.plist里加权限描述,操作步骤如下:
- 打开Xcode项目,在左侧导航栏找到你的XCUITest Target(一般叫
[你的App名]UITests) - 选中这个Target,切换到Info标签页
- 点击
+号添加权限键:- 如果只需要读取照片,加
Privacy - Photo Library Usage Description,填写描述文本(比如"测试需要读取照片库") - 如果是iOS 14及以上,要是需要读取所有照片,还要加
Privacy - Photo Library Limited Usage Description,同样填描述 - 要是需要写入照片(比如上传后存回相册),再加
Privacy - Photo Library Additions Usage Description
- 如果只需要读取照片,加
二、在测试代码里请求权限并访问照片
默认情况下测试应用不会自动获得权限,得主动请求,然后才能读取你用simctl addmedia添加的图片:
- 先导入必要的框架:
import XCTest import Photos
- 在测试类的
setUp里请求权限(用XCTestExpectation等待异步操作完成,避免测试跑飞):
override func setUp() { super.setUp() continueAfterFailure = false // 请求照片库读取权限 let permissionExpectation = expectation(description: "等照片库权限请求完成") PHPhotoLibrary.requestAuthorization { status in switch status { case .authorized, .limited: print("权限拿到啦!") default: print("权限被拒了,没法访问照片库哦") } permissionExpectation.fulfill() } waitForExpectations(timeout: 5, handler: nil) }
- 编写测试用例读取照片并上传:
func testFetchPhotoAndUploadToServer() { // 从照片库获取最新的图片 let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] let imageAssets = PHAsset.fetchAssets(with: .image, options: fetchOptions) guard let targetAsset = imageAssets.firstObject else { XCTFail("照片库没找到图片!你是不是用simctl加错模拟器了?") return } // 把PHAsset转成可以上传的Data let loadImageExpectation = expectation(description: "等图片加载完成") var imageData: Data? let imageManager = PHImageManager.default() imageManager.requestImageDataAndOrientation(for: targetAsset, options: nil) { data, _, _, _ in imageData = data loadImageExpectation.fulfill() } waitForExpectations(timeout: 10, handler: nil) guard let uploadData = imageData else { XCTFail("没法获取图片数据") return } // 调用上传方法把图片发到服务器 uploadImage(data: uploadData) } // 写个简单的上传示例(根据你的服务器接口调整参数和格式) private func uploadImage(data: Data) { guard let uploadURL = URL(string: "https://your-server-endpoint.com/upload") else { XCTFail("服务器URL无效") return } var request = URLRequest(url: uploadURL) request.httpMethod = "POST" // 构建multipart/form-data请求(大多数文件上传接口用这个格式) let boundary = "TestUploadBoundary-\(UUID().uuidString)" request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") var requestBody = Data() // 添加上传字段 requestBody.append("--\(boundary)\r\n".data(using: .utf8)!) requestBody.append("Content-Disposition: form-data; name=\"image\"; filename=\"test-photo.jpg\"\r\n".data(using: .utf8)!) requestBody.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!) requestBody.append(data) requestBody.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!) request.httpBody = requestBody // 等待上传完成 let uploadExpectation = expectation(description: "等图片上传完成") URLSession.shared.dataTask(with: request) { data, response, error in defer { uploadExpectation.fulfill() } if let err = error { XCTFail("上传失败:\(err.localizedDescription)") return } guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { XCTFail("服务器返回错误状态码") return } print("图片上传成功啦!") }.resume() waitForExpectations(timeout: 30, handler: nil) }
三、关于xcrun simctl addmedia的小提醒
你用这个命令加图片的时候,要确保是给当前运行测试的模拟器加的:
- 先通过
xcrun simctl list查看所有模拟器的UDID - 指定UDID添加图片:
xcrun simctl addmedia <你的模拟器UDID> /path/to/your/image.jpg - 加完之后,测试应用必须拿到权限才能看到这些图片,因为权限是测试应用单独的,和SUT没关系
四、常见坑排查
- 还是看不到图片?去模拟器的设置->隐私与安全性->照片里看看测试应用的权限是不是开着的,或者检查Info.plist里的权限描述有没有加对
- 上传失败?先确认服务器URL能正常访问,要是用HTTPS,检查证书是不是信任的;另外测试里的网络请求一定要用
XCTestExpectation等待,不然测试会提前结束 - 异步操作出问题?所有涉及权限请求、图片加载、网络请求的异步操作,都要用
waitForExpectations等待完成,不然测试会直接跳过这些逻辑
内容的提问来源于stack exchange,提问作者ablarg
相关产品推荐
相关产品推荐

