23

Xcode 7开始,我们有了一个很好的 UI 测试 API。主要是我很满意。唯一的问题与速度有关。

一开始,一个普通的 UI 测试用例(大约 15 个动作)运行了大约25 秒。然后我完全嘲笑网络。现在需要20 秒。考虑到时间仅由动画和启动时间(1 秒甚至更少)占用的事实,我认为必须有一种方法可以加快速度。

4

8 回答 8

32

在 UI 测试运行时尝试设置此属性:

UIApplication.shared.keyWindow?.layer.speed = 100

这是我的设置方式:

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    if ProcessInfo.processInfo.arguments.contains("UITests") {
        UIApplication.shared.keyWindow?.layer.speed = 100
    }
}

在我的 UI 测试中:

class MyAppUITests: XCTestCase {

    // MARK: - SetUp / TearDown

    override func setUp() {
        super.setUp()

        let app = XCUIApplication()
        app.launchArguments = ["UITests"]
        app.launch()
    }
}

这篇博文中还有一些更方便的技巧。

于 2016-05-18T03:28:51.997 回答
12

另一种可能性是完全禁用动画:

[UIView setAnimationsEnabled:NO];

斯威夫特 3:

UIView.setAnimationsEnabled(false)
于 2016-05-24T15:01:05.073 回答
6

在@Mark 回答之后,Swift 3版本:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    if ProcessInfo.processInfo.arguments.contains("UITests") {
        UIApplication.shared.keyWindow?.layer.speed = 200
    }
}

在你的 ui 测试文件上:

override func setUp() {
    super.setUp()

    // Put setup code here. This method is called before the invocation of each test method in the class.

    let app = XCUIApplication()
    app.launchArguments = ["UITests"]
    app.launch()
于 2017-02-24T12:47:57.153 回答
3

将其添加到 didFinishLaunch

[UIApplication sharedApplication].keyWindow.layer.speed = 2;

默认值为 1,设为 2 使其速度加倍。

于 2017-06-09T08:03:44.593 回答
2

并行运行它们。

如果您只有 1 台构建机器,则可以使用 Bluepill:https ://github.com/linkedin/bluepill

如果有多台机器,可以使用 Emcee:https ://github.com/avito-tech/Emcee (也适用于单机设置)

我们有 50 小时的 UI 测试,Emcee 允许我们在 1 小时内运行它们。有几个技巧可以让 UI 测试更快,但如果你不并行运行它们就毫无意义。例如,你不能让你的 25 秒测试在 0.5 秒内运行。


技巧:

  1. 运行 XCUIApplication 而不重新安装它:
XCUIApplication(
    privateWithPath: nil,
    bundleID: "your.bundle.id"
)

注意:您应该XCUIApplication().launch()在每次启动 XCUI 测试运行程序时至少启动一次应用程序以安装应用程序。这需要使用私有 API。

  1. 您可以将某些内容移动到后台线程。例如
let someDataFromApi = getSomeData() // start request asynchronously and immediately return
launchApp() // this can be few seconds
useInTest(someDataFromApi) // access to data will wait request to finish

你可以让代码看起来没有异步的东西,这对 QA 来说会更容易。我们想实现这个,但我们没有,所以这只是一个想法。

  1. 切换到 EarlGrey 并进行持续几秒钟的测试(但它们不会是黑匣子)。

  2. 如果您有深层链接,则通过深层链接打开屏幕。

  3. 使用大量私有 API 和其他技巧。例如:您可以调用一些私有 API,而不是通过 UI 进入设置应用程序然后重置隐私设置。

  4. 永远不要使用长时间的睡眠。使用轮询。

  5. 加快动画速度。不要禁用它们!

  6. 将一些标志从 UI 测试传递到应用程序以跳过初始警报/教程/弹出窗口。可以节省很多时间。确保至少有 1 个测试来检查这些警报是否有效。

于 2019-02-03T15:09:41.483 回答
2

我想在快照测试期间禁用所有动画。我能够通过禁用核心动画和 UIView 动画来实现这一点,如下所示。

请注意,因为我的应用程序使用的故事板UIApplication.shared.keyWindow在启动时为零,所以我通过window直接引用属性来访问 UIWindow。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    if ProcessInfo.processInfo.arguments.contains("SnapshotTests") {
        // Disable Core Animations
        window?.layer.speed = 0
        // Disable UIView animations
        UIView.setAnimationsEnabled(false)
    }
    return true
}
于 2019-01-28T14:17:02.460 回答
1

我将我的 UITests 时间减少了 30%,遵循所有步骤:

运行应用程序时,添加参数:

let app = XCUIApplication()

override func setUp() {
    super.setUp()

    continueAfterFailure = false
    app.launchArguments += ["--Reset"]
    app.launch()
}

现在,在您的 AppDelegate 中添加:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    setStateForUITesting()
}

static var isUITestingEnabled: Bool {
    get {
        return ProcessInfo.processInfo.arguments.contains("--Reset")
    }
}

private func setStateForUITesting() {
    if AppDelegate.isUITestingEnabled {
        // If you need reset your app to clear state
        UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)

        // To speed up your tests
        UIApplication.shared.keyWindow?.layer.speed = 2
        UIView.setAnimationsEnabled(false)
    }
}

在您的代码中,要验证是否处于测试模式,您可以使用:

if AppDelegate.isUITestingEnabled {
    print("Test Mode")
}

此外,为了可以wait在元素加载时创建此扩展:

import XCTest

extension XCUIElement {
    func tap(wait: Int, test: XCTestCase) {
        if !isHittable {
            test.expectation(for: NSPredicate(format: "hittable == true"), evaluatedWith: self, handler: nil);
            test.waitForExpectations(timeout: TimeInterval(wait), handler: nil)
        }
        tap()
    }
}

像这样使用:

app.buttons["start"].tap(wait: 20, test: self)
于 2019-05-29T16:03:07.893 回答
0

请注意,keyWindow自 iOS 13 起已弃用。具体而言, UIApplication.sharedApplication.keyWindowself.window.keyWindowAppDelegate 中,两者都返回 nil。这个答案说循环UIApplication.shared.windows并找到一个为isKeyWindow真的,但在我使用ios14的测试中,即使是我唯一的窗口也返回假。最后,设置self.window.layer.speed对我有用。

于 2021-06-07T15:31:29.073 回答