核心内容摘要
爱情岛论坛首页
稳定性测试测试应用程序在长时间运行过程中是否存在内存泄漏、崩溃等问题以确保应用程序具有较高的稳定性和可靠性。
对于安卓端官方提供了很好的稳定性测试工具monkey。
相比较而言iOS则没有而且当前网络上似乎也没有很好的第三方工具可以使用因此只能自己写了。
我们要开发的iOS稳定性测试程序应该至少包含以下内容持续随机触发UI事件崩溃重启测试不中断日志记录首先我们确定以上设想的可行性然后再制定实施方案。
在iOS原生开发语言swift和object-C中提供了可进行单元测试和UI测试的XCTest框架而同样可进行移动端UI测试的第三方框架还有Appium等但相比较第三方的开源框架原生的XCTest框架性能更好且更稳定因此这里我们选择基于swift语言和XCTest框架来开发。
XCTest框架提供了非常全面的启动App和UI操作相关的API接口 因此
2两点完全可以实现当然第三点的日志记录的实现也同样不会有什么问题。
接下来就是具体实施了。
首先我们创建一个用来执行测试的主类StabilityTestRunner然后再编写代码去实现以上三点。
持续随机触发UI事件让我们拆分一下随机触发UI事件实际上包含两部分随机UI元素和随机的UI操作。
那么随机生成UI元素func randomElement(of types: [ElementType]) - XCUIElement? { var allElement:[XCUIElement] [] for type in types { if !self.exists{ break } var elements: [XCUIElement] if self.alerts.count 0 { elements self.alerts.descendants(matching: type).allElementsBoundByIndex }else { elements self.descendants(matching: type).allElementsBoundByIndex } let filteredElements elements.filter { element in if !element.exists { return false } if !element.isHittable || !element.isEnabled { return false // Filter out non clickable and blocked elements. } return true } allElement.append(contentsOf: filteredElements) } return allElement.randomElement() }随机生成UI操作/** Random execution of the given UI operation. - parameter element: Page Elements. - parameter actions: Dictionary objects containing different UI operations. */ private func performRandomAction(on element: XCUIElement, actions: [String: (XCUIElement) - ()]) { let keys Array(actions.keys) let randomIndex Int.random(in:
.keys.count) let randomKey keys[randomIndex] let action actions[randomKey] if action nil { return } if !element.exists { return } if !element.isHittable { return } Utils.log(step\(currentStep): \(randomKey) \(element.description)) action!(element) }持续测试和崩溃重启while !isTestingComplete{ // Randomly select page elements. let element app.randomElement(of: elementType) if element ! nil { currentStep 1 takeScreenshot(element: element!) performRandomAction(on: element!, actions: actions) // Perform random UI operations. XCTWaiter().wait(for: [XCTNSPredicateExpectation(predicate: NSPredicate(format: self %d, XCUIApplication.State.runningForeground.rawValue), object: app)], timeout: stepInterval) if app.state ! .runningForeground { if app.state .notRunning || app.state .unknown { Utils.saveImagesToFiles(images: screenshotData) Utils.saveImagesToFiles(images: screenshotOfElementData, name: screenshot_element) Utils.log(The app crashed. The screenshot before the crash has been saved in the screenshot folder.) } app.activate() } } }日志记录记录截图并标记UI元素private func takeScreenshot(element: XCUIElement) { let screenshot app.windows.firstMatch.screenshot().image if screenshotData.count 3 { let minKey screenshotData.keys.sorted().first! screenshotData.removeValue(forKey: minKey) } let screenshotWithRect Utils.drawRectOnImage(image: screenshot, rect: element.frame) screenshotData[currentStep] screenshotWithRect.pngData() let screenshotOfElement element.screenshot().pngRepresentation if screenshotOfElementData.count 3 { let minKey screenshotOfElementData.keys.sorted().first! screenshotOfElementData.removeValue(forKey: minKey) } screenshotOfElementData[currentStep] screenshotOfElement }通过文本日志记录测试执行过程static func log(_ message: String) { print(message) let dateFormatter DateFormatter() dateFormatter.dateFormat yyyy-MM-dd HH:mm:ss let dateString dateFormatter.string(from: Date()) let fileManager FileManager.default do { try fileManager.createDirectory(atPath: logSavingPath, withIntermediateDirectories: true, attributes: nil) } catch { print(Error creating images directory: \(error)) } var fileURL: URL if #available(iOS
1
0, *) { fileURL URL.init(filePath: logSavingPath).appendingPathComponent(log.txt) } else { fileURL URL.init(fileURLWithPath: logSavingPath).appendingPathComponent(log.txt) } do { try \(dateString) \(message).appendLineToURL(fileURL: fileURL) } catch { print(Error writing to log file: \(error)) }日志导出// To add the log files to the test results file, you can view it on your Mac. The test results file path: /User/Library/Developer/Xcode/DerivedData/AppStability-*/Logs. let zipFile \(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])/Logs.zip let attachment XCTAttachment(contentsOfFile: URL(fileURLWithPath: zipFile)) attachment.name Logs attachment.lifetime .keepAlways // Add the Logs.zip file to the end of test result file. add(attachment) Utils.log(The logs for test steps has been added to the end of test result file at /User/Library/Developer/Xcode/DerivedData/AppStability-*/Logs)注以上代码只是主体实现了解相关细节可通过GitHub或Gitee查阅完整代码。
总结总的来说实现起来并不是很困难当然从程序使用角度而言用户可自定义随机UI事件的UI元素范围和UI操作的范围以及测试执行的时长和时间间隔因此需要对ios应用程序和Xcode的使用以及iOS UI事件有一定的了解具体使用可查看完整工程中的示例。
感谢每一个认真阅读我文章的人礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走这些资料对于【软件测试】的朋友来说应该是最全面最完整的备战仓库这个仓库也陪伴上万个测试工程师们走过最艰难的路程希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取