基于Python的APP性能测试和框架
获取设备性能数据
转载:https://testerhome.com/topics/9513
- 尽量不要用split切割的方式取值,因为不同手机取值不一样,还可能会出现数组越界 取cpu占用情况时,不要用top和dump
- cpuinfo,因为他们拿到的是几个cpu的值,会出现超过100%
得到cpu几核
def get_cpu_kel(devices):
cmd = "adb -s " + devices + " shell cat /proc/cpuinfo"
print(cmd)
output = subprocess.check_output(cmd).split()
sitem = ".".join([x.decode() for x in output]) # 转换为string
return len(re.findall("processor", sitem))
取cpu使用情况
'''
每一个cpu快照均
'''
def totalCpuTime(devices):
user=nice=system=idle=iowait=irq=softirq= 0
'''
user:从系统启动开始累计到当前时刻,处于用户态的运行时间,不包含 nice值为负进程。
nice:从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间
system 从系统启动开始累计到当前时刻,处于核心态的运行时间
idle 从系统启动开始累计到当前时刻,除IO等待时间以外的其它等待时间
iowait 从系统启动开始累计到当前时刻,IO等待时间(since 2.5.41)
irq 从系统启动开始累计到当前时刻,硬中断时间(since 2.6.0-test4)
softirq 从系统启动开始累计到当前时刻,软中断时间(since 2.6.0-test4)
stealstolen 这是时间花在其他的操作系统在虚拟环境中运行时(since 2.6.11)
guest 这是运行时间guest 用户Linux内核的操作系统的控制下的一个虚拟CPU(since 2.6.24)
'''
cmd = "adb -s " + devices +" shell cat /proc/stat"
print(cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
res = output.split()
for info in res:
if info.decode() == "cpu":
user = res[1].decode()
nice = res[2].decode()
system = res[3].decode()
idle = res[4].decode()
iowait = res[5].decode()
irq = res[6].decode()
softirq = res[7].decode()
print("user=" + user)
print("nice=" + nice)
print("system=" + system)
print("idle=" + idle)
print("iowait=" + iowait)
print("irq=" + irq)
print("softirq=" + softirq)
result = int(user) + int(nice) + int(system) + int(idle) + int(iowait) + int(irq) + int(softirq)
print("totalCpuTime"+str(result))
return result
'''
每一个进程快照
'''
def processCpuTime(pid, devices):
'''
pid 进程号
utime 该任务在用户态运行的时间,单位为jiffies
stime 该任务在核心态运行的时间,单位为jiffies
cutime 所有已死线程在用户态运行的时间,单位为jiffies
cstime 所有已死在核心态运行的时间,单位为jiffies
'''
utime=stime=cutime=cstime = 0
cmd = "adb -s "+ devices + " shell cat /proc/" + pid +"/stat"
print(cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
res = output.split()
utime = res[13].decode()
stime = res[14].decode()
cutime = res[15].decode()
cstime = res[16].decode()
print("utime="+utime)
print("stime="+stime)
print("cutime="+cutime)
print("cstime="+cstime)
result = int(utime) + int(stime) + int(cutime) + int(cstime)
print("processCpuTime="+str(result))
return result
'''
计算某进程的cpu使用率
100*( processCpuTime2 – processCpuTime1) / (totalCpuTime2 – totalCpuTime1) (按100%计算,如果是多核情况下还需乘以cpu的个数);
cpukel cpu几核
pid 进程id
'''
def cpu_rate(pid, cpukel, devices):
# pid = get_pid(pkg_name)
processCpuTime1 = processCpuTime(pid, devices)
time.sleep(1)
processCpuTime2 = processCpuTime(pid, devices)
processCpuTime3 = processCpuTime2 - processCpuTime1
totalCpuTime1 = totalCpuTime(devices)
time.sleep(1)
totalCpuTime2 = totalCpuTime(devices)
totalCpuTime3 = (totalCpuTime2 - totalCpuTime1)*cpukel
cpu = 100 * (processCpuTime3) / (totalCpuTime3)
print(cpu)
取men占用情况
cmd = "adb -s " + devices +" shell dumpsys meminfo %s" % (pkg_name)
print(cmd)
output = subprocess.check_output(cmd).split()
s_men = ".".join([x.decode() for x in output]) # 转换为string
print(s_men)
men2 = int(re.findall("TOTAL.(\d+)*", s_men, re.S)[0])
print(men2 )
取电量占用情况
def get_battery(devices):
cmd = "adb -s " + devices + " shell dumpsys battery"
print(cmd)
output = subprocess.check_output(cmd).split()
stderr=subprocess.PIPE).stdout.readlines()
st = ".".join([x.decode() for x in output]) # 转换为string
print(st)
battery2 = int(re.findall("level:.(\d+)*", st, re.S)[0])
writeInfo(battery2, PATH("../info/" + devices + "_battery.pickle"))
return battery2
取wifi,gprs上下行流量
def get_flow(pid, type, devices):
# pid = get_pid(pkg_name)
_flow1 = [[], []]
if pid is not None:
cmd = "adb -s " + devices + " shell cat /proc/" + pid + "/net/dev"
print(cmd)
_flow = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.readlines()
for item in _flow:
if type == "wifi" and item.split()[0].decode() == "wlan0:": # wifi
# 0 上传流量,1 下载流量
_flow1[0].append(int(item.split()[1].decode()))
_flow1[1].append(int(item.split()[9].decode()))
print("------flow---------")
print(_flow1)
break
if type == "gprs" and item.split()[0].decode() == "rmnet0:": # gprs
print("-----flow---------")
_flow1[0].append(int(item.split()[1].decode()))
_flow1[1].append(int(item.split()[9].decode()))
print(_flow1)
break
else:
_flow1[0].append(0)
_flow1[1].append(0)
得到fps
'''
@author fenfenzhong
'''
def get_fps(pkg_name, devices):
_adb = "adb -s " + devices +" shell dumpsys gfxinfo %s" % pkg_name
print(_adb)
results = os.popen(_adb).read().strip()
frames = [x for x in results.split('\n') if validator(x)]
frame_count = len(frames)
jank_count = 0
vsync_overtime = 0
render_time = 0
for frame in frames:
time_block = re.split(r'\s+', frame.strip())
if len(time_block) == 3:
try:
render_time = float(time_block[0]) + float(time_block[1]) + float(time_block[2])
except Exception as e:
render_time = 0
'''
当渲染时间大于16.67,按照垂直同步机制,该帧就已经渲染超时
那么,如果它正好是16.67的整数倍,比如66.68,则它花费了4个垂直同步脉冲,减去本身需要一个,则超时3个
如果它不是16.67的整数倍,比如67,那么它花费的垂直同步脉冲应向上取整,即5个,减去本身需要一个,即超时4个,可直接算向下取整
最后的计算方法思路:
执行一次命令,总共收集到了m帧(理想情况下m=128),但是这m帧里面有些帧渲染超过了16.67毫秒,算一次jank,一旦jank,
需要用掉额外的垂直同步脉冲。其他的就算没有超过16.67,也按一个脉冲时间来算(理想情况下,一个脉冲就可以渲染完一帧)
所以FPS的算法可以变为:
m / (m + 额外的垂直同步脉冲) * 60
'''
if render_time > 16.67:
jank_count += 1
if render_time % 16.67 == 0:
vsync_overtime += int(render_time / 16.67) - 1
else:
vsync_overtime += int(render_time / 16.67)
_fps = int(frame_count * 60 / (frame_count + vsync_overtime))
# return (frame_count, jank_count, fps)
print("-----fps------")
print(_fps)
框架实践简单举例
转载:https://blog.csdn.net/qq_24204451/article/details/77914211
测试用例
# -*- coding: utf-8 -*-
import selenium
from appium import webdriver
import os
import time
import unittest
import HTMLParser
#Appium环境配置
PATH = lambda p: os.path.abspath(
os.path.join(os.path.dirname(__file__), p)
)
class JdANDROIDTests(unittest.TestCase):
def setUp(self):
desired_caps = {}
desired_caps['platformName'] = 'Android' #设置平台
desired_caps['platformVersion'] = '6.0.1' #系统版本
desired_caps['deviceName'] = '192.168.199.179:5555'
desired_caps['autoLaunch'] = 'true' #是否自动启动
desired_caps['appPackage'] = 'com.Jd' #包名
desired_caps['appActivity'] = 'com.Jd.splash.SplashActivity'
desired_caps['unicodeKeyboard'] = 'true'
desired_caps['resetKeyboard'] = 'true'
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
self.x = self.driver.get_window_size()['width']
self.y = self.driver.get_window_size()['height']
def test_mjd(self):
time.sleep(5)
self.driver.get('https://m.jd.com/')
time.sleep(3)
search = self.driver.find_element_by_xpath('.//*[@id="index_newkeyword"]')
search.click()
search.send_keys('iwatch')
self.driver.find_element_by_xpath('.//*[@id="index_search_submit"]/span').click()
for i in range(1,5):
time.sleep(3)
pro = './/*[@id="searchlist44"]/li['+str(i)+']/a/div[2]/div[1]/span'
self.driver.find_element_by_xpath(pro).click()
time.sleep(3)
self.driver.find_element_by_xpath('.//*[@id="cart1"]/div[2]/a[1]').click()
if i<4:
time.sleep(3)
self.driver.find_element_by_xpath('.//*[@id="m_common_header_goback"]/span').click()
time.sleep(3)
num = int(self.driver.find_element_by_xpath('.//*[@id="carNum"]').text)
if num == i:
print u'购物车已添加'+str(num)+u'件商品'
else:
print u'购物车商品数量不对,请联系相关人员查看'
获取性能数据
def get_cpu(packgename,device_id):
try:
#获取App的CPU占用率的adb命令
re_command = 'adb -s device_id shell dumpsys cpuinfo | grep packgename'
command = re_command.replace('device_id',device_id).replace('packgename',packgename).split(' ')
# 使用python自带包subprocess开启一个子线程执行shell命令,并读取输出,将标准输出存入本地文件
file = os.path.abspath('.') + datetime.now().strftime('%Y%m%d%H%M%S') + 'Pss.log'
f = open(file, 'wb')
p = subprocess.Popen(args=command,stdout=f,stderr=subprocess.PIPE)
p.wait()
f.closed
except EOFError,E:
print E
def get_Pss(packgename,device_id):
try:
# 获取App的物理运行内存的adb命令
re_command = 'adb -s device_id shell dumpsys meminfo | grep packgename'
command = re_command.replace('device_id', device_id).replace('packgename', packgename).split(' ')
# 使用python自带包subprocess开启一个子线程执行shell命令,并读取输出,将标准输出存入本地文件
file = os.path.abspath('.')+datetime.now().strftime('%Y%m%d%H%M%S')+'Pss.log'
f = open(file,'wb')
p = subprocess.Popen(args=command, stdout=f, stderr=subprocess.PIPE)
p.wait()
f.closed
except EOFError, E:
print E
def get_power(device_id):
try:
# 获取电量的adb命令
re_command = 'adb -s device_id shell dumpsys battery'
command = re_command.replace('device_id', device_id).split(' ')
# 使用python自带包subprocess开启一个子线程执行shell命令,并读取输出,将标准输出存入本地文件
file = os.path.abspath('.')+datetime.now().strftime('%Y%m%d%H%M%S')+'Pss.log'
运行实践
def thead_main():
#构造多线程对象执行池,对象接收一个要执行的方法名,如果方法需要传参通过args选项实现
theads = []
t1 = threading.Thread(target=test_mjd)
theads.append(t1)
t2 = threading.Thread(target=get_cpu,args=('com.Jd','192.168.199.179:5555'))
theads.append(t2)
t3 = threading.Thread(target=get_Pss, args=('com.Jd', '192.168.199.179:5555'))
theads.append(t3)
t4 = threading.Thread(target=get_power, args=('192.168.199.179:5555',))
theads.append(t4)
for t in theads:
t.start() #start方法开启一个执行池的运行
if __name__ == '__main__':
thead_main()