如何在 Xcode 中的 UITest 之间保持应用程序打开

How do I keep the app open between UITests in Xcode

我有一系列 UITest,我想 运行 作为单独的测试,但我不想在每次测试之间重新启动应用程序。我怎样才能启动该应用程序并使其保持打开状态,以便它不会在测试之间关闭和重新启动。

我尝试将 XCUIApplication().launch() 放入 init() 中,但出现错误。

在您的 setUp() 方法中,删除 [[[XCUIApplication alloc] init] launch]; 并将其放入您将要执行的第一个测试中。

例如,

如果您有测试:testUI()、testUIPart2()、testUIPart3() 等,并且它按此顺序运行,请将 [[[XCUIApplication alloc] init] launch]; 放入 testUI() 的第一行,不要放在其他地方.

改进@James Goe 的回答 -

为了避免所有这些重新启动,但保留 运行 单独测试的能力 - 而不关心它们 运行 的顺序 - 你可以:

class MyTests: XCTestCase {
    static var launched = false

    override func setUp() {
        if (!MyTests.launched) {
            app.launch()
            MyTests.launched = true
        }

(当然,既然您没有重新启动您的应用程序,您就必须更加关心状态,但那是另一回事了。它肯定更快。)

这个问题有点老了,但是 XCTestCase 有一个 class 函数用于 setup()tearDown(),它在第一个测试之前和最后一个测试完成之后执行。如果您将 XCUIApplication() 创建为单例(比如 XCUIAppManager),您可以将 XCUIAppManager.shared.launchApp() 调用放在 override class func setup() 方法中......这只会为每个 XCTestCase 启动应用程序一次(包含多个测试)

override class func setUp() { // 1.
    super.setUp()
    // This is the setUp() class method.
    // It is called before the first test method begins.
    // Set up any overall initial state here.
}

https://developer.apple.com/documentation/xctest/xctestcase/understanding_setup_and_teardown_for_test_methods

示例应用程序管理器单例实现:

import XCTest

class XCUIAppManager {
    static let shared = XCUIAppManager()
    let app = XCUIApplication(bundleIdentifier: "com.something.yourAppBundleIdentifierHere")
    private(set) var isLaunched = false

    private init() {}

    func launchApp() {
        app.launch()
        isLaunched = true
    }
}

这是另一种允许在每次测试中启动普通或 non-common 应用程序的方法。

您可以通过创建自定义 XCUIApplication 并在您的应用启动中包含状态来实现,如下所示。

import XCTest

class MyUIApplication: XCUIApplication {
    private(set) var isLaunched = false
    static let shared = MyUIApplication()

    private override init() {
        super.init()
        
        // add your launch arguments and environment keys
        launchArguments += ["isRunningTests"]
        launchEnvironment["state"] = "InitState"
    }

    func launchIfNeeded(at state: AppState) {
        if !isLaunched {
            launch(at: state)
        }
    }

    func launch(at state: AppState) {
        switch state {
        case .home:
            launchEnvironment["state"] = "InitState"
        ...
        }

        launch()
        isLaunched = true
    }
}

上述解决方案的测试用例示例:

class MyViewControllerTests: XCTestCase {
    let app = VFGUIApplication.shared

    override func setUp() {
        super.setUp()

        app.launchIfNeeded(at: .home)
    }
}

如果您正在与团队合作并且您希望确保根据 pre-defined launchArgumentslaunchEnvironment 等正确执行发布,那么这是更可取的。