游戏测试 时隔两月,这次听取大佬的意见,优化了下之前的脚本

了不起的QA · 2019年05月22日 · 最后由 陈子昂 回复于 2019年10月03日 · 3999 次阅读

之前呢,写了个脚本看内存占用的,https://testerhome.com/topics/18400 地址在这。但是有个问题当时并不能解决:所有的数据都是写进了 excel 中,只能在制表后看看内存走向,峰值等,看表的时候并不能知道内存攀升的时候做了什么操作,就比较鸡肋。
这次呢!有去了解大佬推荐的 pyecharts 这个库,很好的解决了这个问题。并且能节省很多人工的操作。
现在的实现思路是:依然使用 adb 去获得时间节点的内存数据,将这些数据都保存在对应的 list 中,并使用 pyecharts 将数据做成折现图保存为 html 文件,为了实现类似于即时查看的功能,引入了 selenium 库,打开这个 html 文件,并且在新数据写入并覆盖 html 文件后能刷新页面,实现每次数据获得后都能即时看到变化。
先看下具体的实现效果

那这个库在使用上上手很容易,基本上 2 小时就能基本会用。

# -*- coding: utf-8 -*-
import subprocess
import time
import os
from pyecharts import Line
from selenium import webdriver

time_value = []
JavaHeap_value = []
NativeHeap_value = []
Code_value = []
Stack_value = []
Graphics_value = []
PrivateOther_value = []
System_value = []
TOTAL_value = []
TOTAL_SWAP_PSS_value = []


# cmd命令执行代码
def run_cmd(cmd):
    """执行CMD命令"""
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    return [i.decode() for i in p.communicate()[0].splitlines()]


# 获取APK的名称
def get_apk_info():
    """获取apk的package,activity名称
        :return: list  eg ['com.android.calendar',
        'com.meizu.flyme.calendar.AllInOneActivity']
    """
    result = os.popen(
        'adb shell dumpsys activity top | find "ACTIVITY"').read()
    return result.splitlines()[-1].split()[1].split('/')


# 内存占用情况
def get_mem_using(package_name=None):
    """查看apk的内存占用
    :param package_name:
    :return: 单位KB
    """
    if not package_name:
        package_name = get_apk_info()[0]
    results = run_cmd("adb shell dumpsys meminfo {}".format(package_name))
    for index, result in enumerate(results):
        if result.strip().startswith('Java Heap'):
            return results[index:index + 9]


# 对cmd格式进行重组,返回成dict
def main():
    dicts = {}
    result = get_mem_using()
    for i in result[:len(result) - 2]:
        if i.strip():
            dicts[i.split(':')[0].strip()] = i.split(':')[1].strip()
    p = result[-1].split('TOTAL')
    dicts[('TOTAL' + p[1]).split(':')[0]
          ] = ('TOTAL' + p[1]).split(':')[1].strip()
    dicts[('TOTAL' + p[2]).split(':')[0]
          ] = ('TOTAL' + p[2]).split(':')[-1].strip()
    return dicts


# pyecharts方法
def pyecharts_set(dicts, i):
    time_value.append(i * 5)
    # 获得的数据均为KB在图表中不能显示微小变化,以四舍五入方式转为MB
    JavaHeap_value.append(round(int(dicts['Java Heap']) / 1024))
    NativeHeap_value.append(round(int(dicts['Native Heap']) / 1024))
    Code_value.append(round(int(dicts['Code']) / 1024))
    Stack_value.append(round(int(dicts['Stack']) / 1024))
    Graphics_value.append(round(int(dicts['Graphics']) / 1024))
    PrivateOther_value.append(round(int(dicts['Private Other']) / 1024))
    System_value.append(round(int(dicts['System']) / 1024))
    TOTAL_value.append(round(int(dicts['TOTAL']) / 1024))
    TOTAL_SWAP_PSS_value.append(round(int(dicts['TOTAL SWAP PSS']) / 1024))
    line = Line('APP_Summary HTML')
    line.add('Java Heap', time_value, JavaHeap_value, is_smooth=True)
    line.add('Native Heap', time_value, NativeHeap_value, is_smooth=True)
    line.add('Code', time_value, Code_value, is_smooth=True)
    line.add('Stack', time_value, Stack_value, is_smooth=True)
    line.add('Graphics', time_value, Graphics_value, is_smooth=True)
    line.add('Private Other', time_value,
             PrivateOther_value, is_smooth=True)
    line.add('System', time_value, System_value, s_smooth=True)
    line.add('TOTAL', time_value, TOTAL_value,
             is_smooth=True, mark_point=['average', 'max'])
    line.add('TOTAL SWAP PSS', time_value,
             TOTAL_SWAP_PSS_value, is_smooth=True)
    line.render('APP_Summary.html')


if __name__ == '__main__':
    i = 1
    driver = webdriver.Chrome()
    while True:
        print("写入第 {} 次数据!".format(i))
        dicts = main()
        if i == 1:
            # init_to_excel(dicts)
            pyecharts_set(dicts, i)
            driver.get(
                r'C:\...\...\APP_Summary.html')  # 这里需要填写绝对路径,相对路径是相对与chromedriver的
        else:
            # add_to_excel(dicts, i)
            pyecharts_set(dicts, i)
            driver.refresh()  # 刷新html
        time.sleep(5)
        i += 1

代码里面的 get_apk_info() 方法和之前的写法有区别,主要是我的手机使用之前的 adb 代码 adb shell dumpsys activity top 会多出来两个 com.miui 之类的东西,类似于
导致在打开应用的时候代码尝试获取的是 miui 的内存占用。于是就会报错。所以换用了新的 adb 命令。并且实验了下,你当前打开的 app 就是这个命令结果的最后一个
https://testerhome.com/topics/1462adb参考地址

现在还想解决下来的问题:
1、有没有更好的打开 html 这个文件的手段,费劲用了 selenium 只用了个 refresh() 方法,感觉很蠢
2、在这个代码里面的循环是否可以有种手段监听下我的键盘操作好暂停或者直接结束代码
3、其实这样的字段数据还是过多,想问下一般的数据参考是哪些,想把其他的字段数据去掉,看起来更简洁些,虽说这个 html 中可以隐藏其他字段数据 233333

共收到 8 条回复 时间 点赞
edsion 回复

感谢,我去了解下

感觉 pyecharts 并不好用,还不如直接用 echarts,用 django 加上 ajax 去实现页面展示和局部刷新。不过你这个方法代码少一些,不集成到测试平台,只是平时看看,还挺简便的

fengzx120 回复

明白了,会慢慢学的,谢谢

赞,也搞过这个,还不错,不过没有实时去刷新这个页面,只是收集数据,用 pyecharts 展示,浏览器直接打开的

可以考虑试试,把数据写到一个 json 文件中,用 js 定时读取 json 文件,并使用前端图表如 echars 这样的插件来完成展示,定时刷新

youya24k 回复

好的

第二个办法解决 共享变量。
另外起一个线程去自动化操作,等操作结束后,修改共享变量值。(固定一个线程修改)
通知监听性能的线程关闭。按上文是 while True 模式,在内部写一个判断共享变量值的条件判断式,因为其他线程行为修改了变量值,一旦修改,这边就写完最后一条数据,然后 break 跳出 while.(等于增加了跳出条件)
多线程需要在 main 区域内使用。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册