前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >iOS 测试 | iOS 自动化性能采集

iOS 测试 | iOS 自动化性能采集

原创
作者头像
霍格沃兹测试开发
修改于 2020-07-15 09:41:39
修改于 2020-07-15 09:41:39
2.4K00
代码可运行
举报
文章被收录于专栏:测吧测试开发测吧测试开发
运行总次数:0
代码可运行

​今天小编跟大家分享一篇来自学院内部学员的技术分享,本文主要介绍了作者在进行 iOS 自动化性能采集的一些经验,希望对大家在进行 iOS 自动化测试时有一些启发。

不要为小事遮住视线,我们还有更大的世界

前言

对于iOS总体生态是比较封闭的,相比Android没有像adb这种可以查看内存、cpu的命令.在日常做性能测试,需要借助xcode中instruments查看内存、cpu等数据.

但是借助instruments比较麻烦、又不能提供命令行.在持续集成中,很难时时的监控app的性能指标.并且现在app发版一般是2周左右,留给做专项测试的时间更少了,那么做核心场景性能测试,肯定是来不及的.

所以需要借助一些自动化工具来减轻手工采集性能指标的工作量.

性能采集项

app中基本性能采集项,内存、cpu、fps、电量等,因为自动化采集中手机设备是插着电脑充电的,所以不能采集电量数据.

已有工具

  • instruments是官方提供的,不能做到自动化采集
  • 腾讯gt,需要在app中集成sdk,有一定的接入成本
  • 第三sdk,类似腾讯gt需要在app集成,可能会有数据泄漏风险

脚本开发

上述的已有工具都不满足,在持续集成中做到自动化采集性能数据,期望的性能测试工具有一下几点:

  • 方便接入
  • 可生成性能报告
  • 可持续化
  • 数据收集精准

所以基于这几点,需要自己开发一套性能采集脚本.

使用官方提供的api做性能采集

获取内存、cpu等

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#import <mach/mach.h>

/**
 *  获取内存
 */
- (NSString *)get_memory {
    int64_t memoryUsageInByte = 0;
    task_vm_info_data_t vmInfo;
    mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
    kern_return_t kernelReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
    if(kernelReturn == KERN_SUCCESS) {
        memoryUsageInByte = (int64_t) vmInfo.phys_footprint;
        NSLog(@"Memory in use (in bytes): %lld", memoryUsageInByte);
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kernelReturn));
    }

    double mem = memoryUsageInByte / (1024.0 * 1024.0);
    NSString *memtostring ;
    memtostring = [NSString stringWithFormat:@"%.1lf",mem];

    return memtostring;
}


/**
 * 获取cpu
 */
- (NSString *) get_cpu{
    kern_return_t kr;
    task_info_data_t tinfo;
    mach_msg_type_number_t task_info_count;

    task_info_count = TASK_INFO_MAX;
    kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count);
    if (kr != KERN_SUCCESS) {
        return [ NSString stringWithFormat: @"%f" ,-1];
    }

    task_basic_info_t      basic_info;
    thread_array_t         thread_list;
    mach_msg_type_number_t thread_count;

    thread_info_data_t     thinfo;
    mach_msg_type_number_t thread_info_count;

    thread_basic_info_t basic_info_th;
    uint32_t stat_thread = 0; // Mach threads

    basic_info = (task_basic_info_t)tinfo;

    // get threads in the task
    kr = task_threads(mach_task_self(), &thread_list, &thread_count);
    if (kr != KERN_SUCCESS) {
        return [ NSString stringWithFormat: @"%f" ,-1];
    }
    if (thread_count > 0)
        stat_thread += thread_count;

    long tot_sec = 0;
    long tot_usec = 0;
    float tot_cpu = 0;
    int j;

    for (j = 0; j < thread_count; j++)
    {
        thread_info_count = THREAD_INFO_MAX;
        kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
                         (thread_info_t)thinfo, &thread_info_count);
        if (kr != KERN_SUCCESS) {
            tot_cpu = -1;
            //return -1;
        }

        basic_info_th = (thread_basic_info_t)thinfo;

        if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
            tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
            tot_usec = tot_usec + basic_info_th->user_time.microseconds + basic_info_th->system_time.microseconds;
            tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * 100.0;
        }

    } // for each thread

    kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
    assert(kr == KERN_SUCCESS);

    NSString *tostring = nil ;
    tostring = [ NSString stringWithFormat: @"%.1f" ,tot_cpu];
    NSLog (@"performance  cpu:%@",tostring);

    return tostring;
}

获取页面vc

上边收集了内存和cpu,还需要在收集数据的同时和页面对应上.这样就清楚了是当前页面的内存和cpu情况.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 *获取当前vc
 */
- (UIViewController *) get_vc {
    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([keyWindow.rootViewController isKindOfClass:[UITabBarController class]]) {
            UITabBarController *tab = (UITabBarController *)keyWindow.rootViewController;
            UINavigationController *nav = tab.childViewControllers[tab.selectedIndex];
            DDContainerController *content = [nav topViewController];
            weakSelf.vc = [content contentViewController];
        }
    });
    return self.vc;
}

获取设备信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 *获取设备名称
 */
- (NSString *) get_devicesName {
    NSString *devicesName = [UIDevice currentDevice].name; //设备名称
    NSLog(@"performance   devicesName:%@", devicesName);
    return devicesName;

}

/*
 *获取系统版本
 */
- (NSString *) get_systemVersion{
    NSString *systemVersion = [UIDevice currentDevice].systemVersion; //系统版本
    NSLog(@"performance   version:%@", systemVersion);
    return systemVersion;
}

/*
 *获取设备idf
 */
- (NSString *) get_idf {
    NSString *idf = [UIDevice currentDevice].identifierForVendor.UUIDString;
    NSLog(@"performance   idf:%@", idf);
    return idf;

}

数据拼接

最终要把内存、cpu等数据拼接成字典的形式,方便输出查看

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
输出log日志的数据格式

{
    "cpu": "0.4",
    "fps": "60 FPS",
    "version": "11.2",
    "appname": "xxxxxx",
    "battery": "-100.0",
    "appversion": "5.0.4",
    "time": "2018-09-07 11:45:24",
    "memory": "141.9",
    "devicesName": "xxxxxx",
    "vcClass": "DDAlreadPaidTabListVC",
    "idf": "8863F83E-70CB-43D5-B6C7-EAB85F3A2AAD"
}

开启子线程采集

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
开一个子线程定时采集数据

/*
 * 性能采集子线程
 */

- (void) performancethread {
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"performance   ======get performance======");

        [self get_fps];

        while (true) {
            DDPerformanceModel *model = [DDPerformanceModel new];
            model.time=[self get_time];
            model.appname=[self get_appname];
            model.appversion=[self get_appversion];
            model.idf =[self get_idf];
            model.devicesName =[self get_devicesName];
            model.version = [self get_systemVersion ];
            model.vcClass = NSStringFromClass([self get_vc].class);
            model.memory = [self get_memory];
            model.battery = [self get_battery];
            model.cpu = [self get_cpu];
            model.fps = self.percount;

            NSString *json = [model modelToJSONString];

//            printf(" getperformance    %s\r\n", [json UTF8String]);
            NSLog(@"getperformance model  %@", json);
            sleep(5);
        }
    }];
    [thread start];

    NSLog(@"performance   ======continue mainblock======");
}

初始化性能采集

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
AppDelegate.m文件中didFinishLaunchingWithOptions方法中用户各种初始化操作,可以在第一行初始化性能采集,
这样app启动以后就可以定时采集数据

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [[getperformance new] performancethread];//获取性能数据

    }

性能采集日志存储

一般来说日志存储都是写入到本地log日志,然后读取.但是有两个问题

  • 需要读写文件代码,对于不熟悉oc的人来说比较难
  • 因为是定时采集,文件IO操作频繁

所以不考虑存储本地log日志的方式,可以在代码中打印出数据,通过截获当前设备运行的日志获取数据.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
模拟器可以使用xcrun simctl命令获取当前设备运行日志,
真机用libimobiledevice获取日志

xcrun simctl spawn booted log stream --level=debug | grep getperformance

输出log日志的数据格式,这块做了json美化,每歌几秒在控制台就打印一次

{
    "cpu": "0.4",
    "fps": "60 FPS",
    "version": "11.2",
    "appname": "xxxxxx",
    "battery": "-100.0",
    "appversion": "5.0.4",
    "time": "2018-09-07 11:45:24",
    "memory": "141.9",
    "devicesName": "xxxxxx",
    "vcClass": "DDAlreadPaidTabListVC",
    "idf": "8863F83E-70CB-43D5-B6C7-EAB85F3A2AAD"
}

如果获取多次数据可以使用shell脚本把命令放到后台,定时写入到logpath中
nohup xcrun simctl spawn booted log stream --level=debug >${logpath} &

代码插入到工程中

因为在持续集成中,每次打取的代码都是不带性能测试代码,这些代码是单独写到文件中.在编译项目前,用shell把代码插入到工程中,这样打出来的包才能有采集性能数据功能.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
scriptrootpath=${2}
AddFiles=${2}"/GetPerformance/performancefiles"
localDDPerformanceModelh=${scriptrootpath}"/GetPerformance/performancefiles/DDPerformanceModel.h"
localDDPerformanceModelm=${scriptrootpath}"/GetPerformance/performancefiles/DDPerformanceModel.m"
localgetperformanceh=${scriptrootpath}"/GetPerformance/performancefiles/getperformance.h"
localgetperformancem=${scriptrootpath}"/GetPerformance/performancefiles/getperformance.m"

addfiles(){

    echo "删除${projectaddpath}中的原性能采集文件"

    rm -rf ${DDPerformanceModelh}
    rm -rf ${DDPerformanceModelm}
    rm -rf ${getperformanceh}
    rm -rf ${getperformancem}

    echo "复制文件到${projectaddpath}路径"

    cp  ${localDDPerformanceModelh} ${projectaddpath}
    cp  ${localDDPerformanceModelm} ${projectaddpath}
    cp  ${localgetperformanceh} ${projectaddpath}
    cp  ${localgetperformancem} ${projectaddpath}

}

性能数据绘制

在手工和自动化使用插入性能测试代码的app,如果截获性能数据后,可以对数据做性能数据绘制.

用Higcharts或者echarts绘制性能走势图

如何在持续集成中使用

monkey和UI自动化中使用,最终会发送一份性能报告.

Demo代码

已经把性能代码脱了主项目,可在Demo代码中编译,github地址:https://github.com/xinxi1990/iOSPerformanceTest

最后

虽然iOS生态封闭,但是对于开发者和测试者还是有一些空间可以利用的.

iOS测试一直都是一个难点,难懂的oc语法和iOS整体框架.如果你开始慢慢接触iOS,会发现iOS测试也并不是那么难,需要一点耐心和一点专心而已.

(文章来源于霍格沃兹测试学院)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
《iOS APP 性能检测》
| 导语 最近组里在做性能优化,既然要优化,就首先要有指标来描述性能水平,并且可以检测到这些指标,通过指标值的变化来看优化效果,于是笔者调研了iOS APP性能检测的一些方法,在此总结一下。 首先,要明确性能检测都需要关注哪些指标,笔者列举了以下几个主要的,后面会详细说: 启动时间 内存占用量,内存告警次数 CPU使用率 页面渲染时间,刷新帧率 网络请求时间,流量消耗 UI阻塞次数,不可操作时长,主线程阻塞超过400毫秒次数 耗电功率 对于静态页面来讲,页面的渲染时间就是从viewDidLoad第一行到vi
腾讯Bugly
2018/03/23
4.8K0
iOS 卡顿监测方案总结
最近在写 APM 相关的东西,所以整理了一下 iOS 中卡顿监测的那些方案,不了解卡顿的原理的可以看这篇文章iOS 保持界面流畅的技巧[1],写的很好。
网罗开发
2021/11/02
2.2K0
iOS 客户端动图优化实践
GIF 和 Animated WebP 是互联网上最主流的动图格式, 但是在 iOS 开发中, 原生的 UIImage 并不直接支持 GIF 以及 Animated WebP 的展示, 因此有了各种优秀的第三方开源方案, 例如 SDWebImage 以及 YYImage 等. 这篇文章将以 QQ 音乐 iOS 端优化动图的实践为基础, 来介绍不同方案的思路以及优劣, 并给出优化的方案. 1. 端内动图展示的问题以及优化结果 长期以来, 部分机型浏览 Q 音的图文流时很容易闪退, 端内其他业务也存在不少动图相
QQ音乐技术团队
2023/05/12
6.1K3
iOS 客户端动图优化实践
克魔助手 - iOS性能检测平台
众所周知,如今的用户变得越来越关心app的体验,开发者必须关注应用性能所带来的用户流失问题。目前危害较大的性能问题主要有:闪退、卡顿、发热、耗电快、网络劫持等,但是做过iOS开发的人都知道,在开发过程中我们没有一个很直观的工具可以实时的知道开发者写出来的代码会不会造成性能问题,虽然Xcode里提供了耗电量检测、内存泄漏检测等工具,但是这些工具使用效果并不理想(如Leak无法发现循环引用造成的内存泄漏)。所以这篇文章主要是介绍一款实时监控app各项性能指标的工具,包括CPU占用率、内存使用量、内存泄漏、FPS、卡顿检测,并且会分析造成这些性能问题的原因。
爱学iOS的小麦子
2024/02/02
2770
CVE-2020-9964:iOS中的信息泄露漏洞分析
2020年09月17日凌晨,苹果终于给所有用户推送了iOS14正式版,并同时发布了iOS 14.0的安全内容更新。阅读该公告后,你将会看到列表中的一个漏洞CVE-2020-9964,这是一个存在于IOSurfaceAccelerator中的安全漏洞。苹果将这个漏洞描述为:“本地用户将能够利用该漏洞读取内核内存数据,这是一个内存初始化问题。”那么在这篇文章中,我们将跟大家介绍有关该漏洞的详细信息。
FB客服
2020/10/27
7610
CVE-2020-9964:iOS中的信息泄露漏洞分析
KSCrash源码分析
0x01 安装过程 1.1 抛砖引玉 KSCrashInstallationStandard* installation = [KSCrashInstallationStandard sharedInstance]; installation.url = [NSURL URLWithString:@"http://put.your.url.here"]; [installation install]; 以上代码是KSCrash的安装代码,[KSCrashInstallationStandard init]底
用户2297838
2018/12/09
4.9K2
KSCrash源码分析
基于tidevice采集iOS性能数据
在iOS性能专项测试会进行采集iOS性能数据,常见性能数据指标: 内存、CPU、FPS、网络、磁盘等。如果了解iOS的同学应该都了解系统生态比较封闭、提供开放接口比较少,想要通过外部采集方式拿到iOS性能数据很难。
测试加
2022/06/21
2K1
基于tidevice采集iOS性能数据
深入剖析 iOS 性能优化
在集合里数据量小的情况下时间复杂度对于性能的影响看起来微乎其微。但如果某个开发的功能是一个公共功能,无法预料调用者传入数据的量时,这个复杂度的优化显得非常重要了。
用户7451029
2020/06/16
1.7K0
深入剖析 iOS 性能优化
带你打造一套 APM 监控系统 之 OOM 问题
内存:由于硬盘读取速度较慢,如果 CPU 运行程序期间,所有的数据都直接从硬盘中读取,则非常影响效率。所以 CPU 会将程序运行所需要的数据从硬盘中读取到内存中。然后 CPU 与内存中的数据进行计算、交换。内存是易失性存储器(断电后,数据消失)。内存条区是计算机内部(在主板上)的一些存储器,用来保存 CPU 运算的中间数据和结果。内存是程序与 CPU 之间的桥梁。从硬盘读取出数据或者运行程序提供给 CPU。
用户2932962
2020/07/15
4.6K0
带你打造一套 APM 监控系统 之 OOM 问题
Redis源码解析——内存管理
        在《Redis源码解析——源码工程结构》一文中,我们介绍了Redis可能会根据环境或用户指定选择不同的内存管理库。在linux系统中,Redis默认使用jemalloc库。当然用户可以指定使用tcmalloc或者libc的原生内存管理库。本文介绍的内容是在这些库的基础上,Redis封装的功能。(转载请指明出于breaksoftware的csdn博客)
方亮
2019/01/16
1.1K0
iOS你不知道的事--Crash分析
原文地址:https://www.jianshu.com/p/56f96167a6e9
iOSSir
2019/06/01
1.5K0
Matrix-iOS 耗电监控
前言 在微信开发过程中,有时会收到一些反馈说,手机使用微信一段时间后就开始发烫了。为了跟进用户的发烫问题,最开始的时候,我们只能通过日志看看用户在这段时间做了些什么操作,努力去复现问题。 会导致手机发烫的原因很多,有可能只是用户在阳光下使用手机;但也有可能真的是微信某个模块代码有问题,导致当前 CPU 占用过高。这很让人头疼。如果能像查卡顿问题一样,有堆栈就好了。 在 WWDC 2018  What’s New in Energy Debugging,苹果推介了 Energy Log 这种日志来查耗电问题
微信终端开发团队
2019/08/09
4.1K0
Matrix-iOS 耗电监控
深入浅出-iOS程序性能优化 (转载)
iOS应用是非常注重用户体验的,不光是要求界面设计合理美观,也要求各种UI的反应灵敏,我相信大家对那种一拖就卡卡卡的 TableView 应用没什么好印象。
tandaxia
2018/09/27
7930
深入浅出-iOS程序性能优化 (转载)
iOS_Crash 四:的捕获和防护
应用层的异常,未被捕获的异常,导致程序向自身发送了 SIGABRT 信号而崩溃,是应用程序自己可控的。对于未被捕获的异常,是可以通过 try-catch 或 NSSetUncaughtExceptionHandler() 机制类捕获的。
mikimo
2023/10/26
7560
19.UI自动化测试框架搭建-性能数据采集
Android 性能稳定性测试工具 mobileperf 开源 (天猫精灵 Android 性能测试-线下篇)
zx钟
2022/12/01
5410
19.UI自动化测试框架搭建-性能数据采集
iOS 开发:『Runtime』详解(四)获取类详细属性、方法
文中示例代码在: bujige / YSC-Class-DetailList-Demo
程序员充电站
2019/08/02
3K0
iOS 优化 - 启动优化
距离上次发完年终总结已经有将近一个月的时间,这一个月来也面试了将近 40 位候选人,或多或少有了一些感想,后面会单独发篇文章跟大家聊一聊这个话题。
CoderStar
2022/09/23
4.1K1
iOS 优化 - 启动优化
利用tidevice+mysql+grafana实现ios性能测试
● 截图 ● 获取手机信息 ● ipa包的安装和卸载 ● 根据bundleID 启动和停止应用 ● 列出安装应用信息 ● 模拟Xcode运行XCTest,常用的如启动WebDriverAgent测试(此方法不依赖xcodebuild) ● 获取指定应用性能(CPU,MEM,FPS) ● 文件操作 ● 其他 支持运行在Mac,Linux,Windows上 官方地址:httpss://github.com/alibaba/taobao-iphone-device
huolong
2023/05/16
6600
利用tidevice+mysql+grafana实现ios性能测试
进制重排
0xffffff`,只是一个虚拟地址,需要通过一张映射表映射后才可以获取到真实的物理地址。并不是所有的虚拟内存都会分配物理内存,只有那些实际使用的
花落花相惜
2021/11/23
6750
【IOS开发进阶系列】IOS常用开发技巧专题
    将AFNetworking添加到预编译头文件,意味着这个框架会被自动的添加到工程的所有源代码文件中。
江中散人_Jun
2023/10/16
5000
【IOS开发进阶系列】IOS常用开发技巧专题
相关推荐
《iOS APP 性能检测》
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档