技术是互联网企业的核心,不管你怎么折腾最终还是以产品质量来说话,万变不离其宗;随着产品构造越来越复杂,对开发人员,对测试人员来说都是一个不小的挑战,这篇博客结合我的项目经验分享一下针对APP性能测试的方法
一直以来对于一个互联网产品,尤其是移动端的App,有一个长期争执的讨论;用户第一注重的到底是丰富实用的功能呢,还是体验优质的性能;我觉得对于测试来说这两者应该是平级,为什么不能将功能性能结合到一起来测试呢?实现的思路很简单,之前我也分享过一篇app自动化测试的博客,接下来要做的就是进行UI自动化的同时获取性能数据,对于一个Android App来说,它的性能数据(per数据)主要分为四大项:CPU占用率(运行时),Pss(实际物理运行内存),Net(流量消耗),power(电量消耗);因为这个power我们必须舍弃传统的数据线连接方式,测试过程中要保证手机设备不接受任何方式的充电操作
基于以上分析,我们将使用异常强大的ADB进行per数据的获取,ADB全称Android Debug Bridge,是一个非常全面的Android软件调试框架,它包含许多丰富的命令,首先我们搭建好ADB开发环境(具体步骤可以百度),然后确保测试用的手机和服务器 (如果是本地那就是你得本机)处在相同网络环境下,然后开启手机USB调试,在服务器或者本机命令行中输入“adb connect 手机IP:5555”(将“手机IP替换成测试手机的ip地址”),然后使用“adb devices”命令查看。如图
这个“192.168.199.179:5555“”就是手机的device_id,这样就完成了无线连接调试,可以放心的去进行下一步;完成了移动设备连接后,我们就要开始进行测试代码的编写了,上面说了需要结合UI自动化测试,也就是说获取per是要和UI自动化同步进行的,所以这里就要引用多线程的方式去编写脚本,下面用一个简单的例子说明整个脚本的流程
# -*- 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'购物车商品数量不对,请联系相关人员查看'
这段代码是个简单的京东商城多次添加购物车的操作UI自动化测试,下面我们在写一个获取per数据(这里只举cpu,电量和内存,流量获取方式比较复杂不在这里占用篇幅了)
的模块:
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'这三段是简单的将获取的性能数据存入到本地文件中,当然最后的做法是存入到数据库,由于占用篇幅过大就不再举例了;下面我们就将这三段脚本和上面的UI自动化测试脚本同步执行吧,需要用到python的多线程模块threading,如下:
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()到这里我们就完美实现了同步测试App的功能和性能,当然这个例子举得非常简单,后续还有分别编写测试报告以及更深入的测试步骤;不过在你技术熟练了之后,这些都不是问题。
通过这篇博客我想建议的是,在做这些测试的时候尽可能的要脱离一些工具(比如腾讯的gt),要自己去写,这样才会熟练,这样才是属于你自己的框架