从Xcode 7开始,我们有一个很好的用于UI测试的API。大多数情况下我对它很满意。唯一的问题与速度有关。
在一开始,普通的UI测试用例(大约15个动作)运行大约25秒。然后我完全嘲笑网络。现在需要20秒。考虑到时间只取决于动画和启动时间(1秒甚至更短),我想,必须有办法加快速度。
在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()
}
}
这个blog post还有一些方便的提示。
另一种可能性是禁用动画:
[UIView setAnimationsEnabled:NO];
斯威夫特3:
UIView.setAnimationsEnabled(false)
关注@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()
在didFinishLaunch中添加它
[UIApplication sharedApplication].keyWindow.layer.speed = 2;
默认值为1,使其速度加倍2倍。
我想在快照测试期间禁用所有动画。我能够通过禁用Core Animation和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
}
并行运行它们。
如果您只有一台构建机器,则可以使用Bluepill:https://github.com/linkedin/bluepill
如果您有多台机器,可以使用Emcee:https://github.com/avito-tech/Emcee(它也适用于单机设置)
我们有50小时的UI测试,而Emcee允许我们在1小时内运行它们。有一些技巧可以让UI测试更快,但如果你没有并行运行它们就毫无意义。例如。你不能让你的25秒测试在0.5秒内运行。
技巧:
XCUIApplication(
privateWithPath: nil,
bundleID: "your.bundle.id"
)
注意:每次启动XCUI测试运行器时,您应该使用XCUIApplication().launch()
启动应用程序至少一次以安装应用程序。这需要使用私有API。
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。我们希望实现这一点,但我们没有,所以这只是一个想法。
我将我的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)