You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UI测试启动后无法修改launchEnvironment,求可行解决方案

解决UI测试运行时动态修改Mock URL的问题

你遇到的问题本质是:应用启动后,测试端修改XCUIApplication的launchEnvironment不会同步到已经运行的应用进程中——因为ProcessInfo的环境变量在应用启动时就被固化了,运行时无法修改。下面给你几个可行的实现方案:

方案一:用UserDefaults传递动态配置

利用UI测试可以通过XCUIApplication操作应用的UserDefaults的特性,把Mock URL配置存在UserDefaults里,应用端在发起请求时优先读取这里的值。

应用端修改

更新URLRequest扩展,优先从UserDefaults取替换URL,没有再回退到环境变量:

extension URLRequest {
    private var isUITestingLaunching: Bool {
        ProcessInfo.processInfo.arguments.contains("UI-TESTING")
    }

    mutating func tryReplaceUITestRequest() {
#if DEBUG
        guard isUITestingLaunching, let path = url?.path else { return }
        
        // 优先从UserDefaults读取动态配置
        let userDefaults = UserDefaults.standard
        if let substitutionUrlString = userDefaults.string(forKey: path) ?? ProcessInfo.processInfo.environment[path],
           let substitutionUrl = URL(string: substitutionUrlString) {
            url = substitutionUrl
        }
#endif
    }
}

测试端修改

在需要更新Mock URL时,直接通过XCUIApplication设置应用的UserDefaults:

func testExample() throws {
    // 1 启动应用,初始配置
    let app = XCUIApplication()
    app.launchArguments += ["UI-TESTING"]
    // 初始配置同时写入UserDefaults(保证启动时生效)
    app.setPreferencesValue("http://localhost:9000/SomeUrlPath", forKey: "HomeSceneStructureUrlPath")
    app.launch()

    // 2 验证初始UI
    ...
    XCTAssertFalse(someElement.waitForExistence(timeout: 10))

    // 3 动态更新Mock URL(直接修改应用的UserDefaults)
    app.setPreferencesValue("http://localhost:9000/OtherUrlPath", forKey: "HomeSceneStructureUrlPath")

    // 4 下拉刷新
    let firstCell = app.tables["someTable"].cells.firstMatch
    let start = firstCell.coordinate(withNormalizedOffset: .zero)
    let finish = firstCell.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 10))
    start.press(forDuration: 0, thenDragTo: finish)

    // 5 验证更新后的UI
    ...
    XCTAssertTrue(settingsButton.waitForExistence(timeout: 10))
}

方案二:用自定义URL Scheme传递指令

给应用注册一个测试专用的URL Scheme,测试端通过发送URL指令,让应用在运行时更新Mock URL配置。

应用端配置

  1. 首先在项目Info的URL Types里添加一个自定义Scheme,比如test-mock。
  2. 创建一个单例来存储动态Mock配置:
class MockURLManager {
    static let shared = MockURLManager()
    private var urlMappings: [String: String] = [:]
    
    func updateMapping(for path: String, url: String) {
        urlMappings[path] = url
    }
    
    func urlForPath(_ path: String) -> String? {
        urlMappings[path]
    }
}
  1. 在SceneDelegate或AppDelegate中处理URL Scheme:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url, url.scheme == "test-mock" else { return }
    
    if let path = url.queryParameters?["path"], let mockUrl = url.queryParameters?["url"] {
        MockURLManager.shared.updateMapping(for: path, url: mockUrl)
    }
}

// 给URL加个解析query参数的扩展
extension URL {
    var queryParameters: [String: String]? {
        guard let components = URLComponents(url: self, resolvingAgainstBaseURL: true),
              let queryItems = components.queryItems else { return nil }
        return queryItems.reduce(into: [String: String]()) { result, item in
            result[item.name] = item.value
        }
    }
}
  1. 更新URLRequest扩展,优先使用单例的配置:
mutating func tryReplaceUITestRequest() {
#if DEBUG
    guard isUITestingLaunching, let path = url?.path else { return }
    
    let substitutionUrlString = MockURLManager.shared.urlForPath(path) 
        ?? ProcessInfo.processInfo.environment[path]
    
    if let urlString = substitutionUrlString, let substitutionUrl = URL(string: urlString) {
        self.url = substitutionUrl
    }
#endif
}

测试端修改

在步骤3中,构造URL并发送给应用:

// 3 动态更新Mock URL
let updateUrl = URL(string: "test-mock://update?path=HomeSceneStructureUrlPath&url=http://localhost:9000/OtherUrlPath")!
app.open(updateUrl)

// 等待配置生效(可选,根据实际情况调整)
sleep(1)

方案三:重启应用(备选)

如果不需要保留当前页面状态,也可以直接重启应用并传入新的launchEnvironment:

// 3 重启应用,传入新配置
app.terminate()
app.launchEnvironment["HomeSceneStructureUrlPath"] = "http://localhost:9000/OtherUrlPath"
app.launch()

这个方案简单但会丢失应用状态,适合不需要保留上下文的测试场景。

内容的提问来源于stack exchange,提问作者Igor Niki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 11:35:31