稳定性测试:测试应用程序在长时间运行过程中是否存在内存泄漏、崩溃等问题,以确保应用程序具有较高的稳定性和可靠性。

对于安卓端,官方提供了很好的稳定性测试工具:monkey。 相比较而言,iOS则没有,而且当前网络上似乎也没有很好的第三方工具可以使用,因此只能自己写了。

我们要开发的iOS稳定性测试程序,应该至少包含以下内容:

  1. 持续随机触发UI事件
  2. 崩溃重启,测试不中断
  3. 日志记录

首先我们确定以上设想的可行性,然后再制定实施方案。在iOS原生开发语言swift和object-C中提供了可进行单元测试和UI测试的XCTest框架,而同样可进行移动端UI测试的第三方框架还有Appium等,但相比较第三方的开源框架,原生的XCTest框架性能更好且更稳定,因此这里我们选择基于swift语言和XCTest框架来开发。XCTest框架提供了非常全面的启动App和UI操作相关的API接口, 因此1、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: 0..<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 16.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")

注:以上代码只是主体实现,了解相关细节可通过GitHubGitee查阅完整代码。

总结

总的来说实现起来并不是很困难,当然从程序使用角度而言,用户可自定义随机UI事件的UI元素范围和UI操作的范围以及测试执行的时长和时间间隔,因此需要对ios应用程序和Xcode的使用以及iOS UI事件有一定的了解,具体使用可查看完整工程中的示例。

app稳定性测试-iOS篇的更多相关文章

  1. APP稳定性测试

    APP稳定性测试-monkey测试     第一篇-App稳定性测试-Monkey(基本操作) 准备工作 1.首先下载好adb工具 2.使用数据线连接电脑,打开usb调试 3.使用win+R打开运行, ...

  2. Monkey Android app稳定性测试工具之Monkey使用教程

    Monkey Android app稳定性测试工具之Monkey使用教程 by:授客 QQ:1033553122 由于篇幅问题,仅提供百度网盘下载链接: Android app稳定性测试工具之Monk ...

  3. APP稳定性测试-monkey执行

    Monkey命令行可用的全部选项 *示例 : adb shell monkey -p cn.lejiayuan.alpha --pct-touch 30 --pct-motion 15 --pct-t ...

  4. App稳定性测试Monkey

    1.$ adb shell monkey <event-count>                <event-count>是随机发送事件数 例:adb shell monk ...

  5. 【测试工具】这些APP实用测试工具,不知道你就out了!

    本期,我将给大家介绍14款实用的测试工具,希望能够帮到大家!(建议收藏) UI自动化测试工具 1. uiautomator2 Github地址:https://github.com/openatx/u ...

  6. iOS App稳定性指标及监测

    一个App的稳定性,主要决定于整体的系统架构设计,同时也不可忽略编程的细节,正所谓"千里之堤,溃于蚁穴",一旦考虑不周,看似无关紧要的代码片段可能会带来整体软件系统的崩溃.尤其因为 ...

  7. app自动测试-微信(iOS)-web-1

    appium 是一个用于app自动测试的工具.目前支持测试iOS, Android, Windows上的app.(github: https://github.com/appium/appium) 其 ...

  8. app测试--稳定性测试

    稳定性测试的概念有2种, 一, 稳定性测试,对应于异常性测试,即发生异常情况时,系统如何反应的测试.包含: 1 交互性测试,被打扰的情况,如来电,短信,低电量等.这些其实在上章的功能测试中有提到. 2 ...

  9. 有谁知道什么工具测试IOS手机上APP的性能软件啊?

    有谁知道什么工具测试IOS手机上APP的性能软件啊?

  10. 移动应用/APP的测试流程及方法

    1. APP测试基本流程 1.1流程图 1.2测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即15个工作日),根据项目情况以及版本质量可适当缩短或延长测试时间.正式测试前先 ...

随机推荐

  1. 通过Windows定时任务执行Python脚本给钉钉群发送消息

    前提:已经存在有成功发送钉钉群机器人消息的python脚本,参考上一篇Python调用钉钉群机器人发送群消息 Windows定时任务设置 1.本机是Win7系统:控制面板->系统和安全-> ...

  2. python 如何以逗号为分隔符输出数组

    l = [1,2,3,4] print(" ".join(str(i) for i in l)) #输出结果为:1 2 3 4(注意,此时4后面没有空格啦) #以逗号为分隔符 l ...

  3. zxb2022习题班16

    (1) 原则:合同中包含多项履约义务的,企业应当按照各单项履约义务所承诺的商品的单独售价的比例,将交易价格分摊至各单项履约义务. 方法:按照A和B商品单独售价的相对比例, 2x22年4月16日 借:合 ...

  4. Latex基础

    文档类 latex提供的基础文档类 article report book proc slides minimal 特殊符号 空格 命令后边空格 1. 字母形式的latex命令忽略其后的所有连续空格, ...

  5. 3、HTTP请求头与响应头

    HTTP简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送 ...

  6. Stram流 - 随笔

    函数式编程 注重函数 - 关注对数据进行了什么操作 流 中间操作 去重 authors.stream() .distinct() ; 查询指定匹配 .filter(new Predicate<A ...

  7. @Resource 和@Autowired注解

    @Autowired注解是根据属性进行注入,例如BaseDAO,BaseDAOImpl继承BaseDAO,可以根据BaseDAO类型进行注入 @Resource 注解是根据属性和名称进行注入,比如Ba ...

  8. 微信小程序 入门总结篇

      页面生命周期 Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { }, ...

  9. .net 生成Excel并保存

    void SaveQuestionToExcel(List<Question> datas, string path) { using (Workbook workbook = new H ...

  10. 如何通过dump文件定位崩溃,解决问题

    1.dump文件是附加堆栈信息的存储文件的简称,文件扩展名".dmp",通过dump文件我们可以得到程序运行某一时刻的堆栈数据.2.当程序意外崩溃后,通常程序会立即中断运行,拿到这 ...