|
1 | 1 | # AndroidTestByPython
|
2 |
| - Android APP使用Python进行性能测试 |
| 2 | + |
| 3 | + Android APP使用Python进行性能测试以及测试框架 |
| 4 | + |
| 5 | +## APP性能测试 |
3 | 6 |
|
4 | 7 | ### APP启动时间
|
5 | 8 |
|
@@ -32,7 +35,7 @@ adb shell am force-stop package
|
32 | 35 | - 停止App命令
|
33 | 36 |
|
34 | 37 | ```shell
|
35 |
| - // 模拟点击back键 |
| 38 | + # 模拟点击back键 |
36 | 39 | adb shell input keyevent 3
|
37 | 40 | ```
|
38 | 41 |
|
@@ -145,5 +148,197 @@ adb shell dumpsys cpuinfo | grep packagename
|
145 | 148 |
|
146 | 149 |
|
147 | 150 |
|
| 151 | +### 流量 |
| 152 | + |
| 153 | +##### 命令 |
| 154 | + |
| 155 | +- 获取进程ID指令 |
| 156 | + |
| 157 | + ```shell |
| 158 | + # windows下用findstr代替grep,否则拿不到结果 |
| 159 | + adb shell ps | grep packagename |
| 160 | + ``` |
| 161 | + |
| 162 | +- 获取进程ID的流量指令 |
| 163 | + |
| 164 | + ```shell |
| 165 | + # pid就是上面指令获取的进程ID |
| 166 | + adb shell cat /proc/pid/net/dev |
| 167 | + ``` |
| 168 | + |
| 169 | +##### 脚本实现 |
| 170 | + |
| 171 | +```python |
| 172 | +# 单次测试过程 |
| 173 | + def test_process(self): |
| 174 | + # 执行获取进程ID的指令 window 下用findstr,Mac下用grep |
| 175 | + cmd = "adb shell ps | findstr org.chromium.webview_shell" |
| 176 | + result = os.popen(cmd) |
| 177 | + # 获取进程ID |
| 178 | + pid = result.readlines()[0].split(" ")[5] |
| 179 | + |
| 180 | + # 获取进程ID使用的流量 |
| 181 | + traffic = os.popen("adb shell cat /proc/" + pid + "/net/dev") |
| 182 | + for line in traffic: |
| 183 | + # 第一个网卡的数据 |
| 184 | + if "eth0" in line: |
| 185 | + # 将所有空行换成# |
| 186 | + line = "#".join(line.split()) |
| 187 | + # 然后按#号进行拆分,获取到收到和发出的流量值 |
| 188 | + receive = line.split("#")[1] |
| 189 | + transmit = line.split("#")[9] |
| 190 | + # 第二个网卡的数据 |
| 191 | + elif "eth1" in line: |
| 192 | + line2 = "#".join(line.split()) |
| 193 | + # 然后按#号进行拆分,获取到收到和发出的流量值 |
| 194 | + receive2 = line2.split("#")[1] |
| 195 | + transmit2 = line2.split("#")[9] |
| 196 | + |
| 197 | + # 计算所有流量之和 |
| 198 | + all_traffic = string.atoi(receive) + string.atoi(transmit) + string.atoi(receive2) + string.atoi(transmit2) |
| 199 | + # 按KB计算流量值 |
| 200 | + all_traffic = all_traffic / 1024 |
| 201 | + # 获取当前时间 |
| 202 | + current_time = self.get_current_time() |
| 203 | + # 将获取到的数据存到数组中 |
| 204 | + self.all_data.append((current_time, all_traffic)) |
| 205 | +``` |
| 206 | + |
| 207 | +运行后的结果: |
| 208 | + |
| 209 | +``` |
| 210 | +timestamp,traffic |
| 211 | +2020-03-13 11:35:36,136535 |
| 212 | +2020-03-13 11:35:41,136791 |
| 213 | +2020-03-13 11:35:47,166458 |
| 214 | +2020-03-13 11:35:52,264812 |
| 215 | +2020-03-13 11:35:57,380940 |
| 216 | +``` |
| 217 | + |
| 218 | +##### 数据分析 |
| 219 | + |
| 220 | +用最后一条流量值减去第一条流量值,得到本次测试运行时消耗掉的流量,然后和以往版本以及竞品进行对比,然后发现流量消耗的问题。 |
| 221 | + |
| 222 | +### 电量 |
| 223 | + |
| 224 | +##### 获取电量 |
| 225 | + |
| 226 | +```shell |
| 227 | +adb shell dumpsys battery |
| 228 | +``` |
| 229 | + |
| 230 | +但是手机连接USB之后,会进入充电状态,测试电量需要在非充电的情况下,所以可以使用下面的命令切换充电状态 |
| 231 | + |
| 232 | +```shell |
| 233 | +# 切换到非充电状态,status = 2 代表充电,非2就是非充电 |
| 234 | +adb shell dumpsys battery set status 1 |
| 235 | +``` |
| 236 | + |
| 237 | +##### 脚本实现 |
| 238 | + |
| 239 | +```python |
| 240 | +# 单次测试过程 |
| 241 | + def test_process(self): |
| 242 | + cmd = "adb shell dumpsys battery" |
| 243 | + result = os.popen(cmd) |
| 244 | + |
| 245 | + for line in result: |
| 246 | + if "level" in line: |
| 247 | + power = line.split(":")[1] |
| 248 | + |
| 249 | + # 获取当前时间 |
| 250 | + current_time = self.get_current_time() |
| 251 | + # 将获取到的数据存到数组中 |
| 252 | + self.all_data.append((current_time, power)) |
| 253 | + |
| 254 | + # 多次执行测试过程 |
| 255 | + def run(self): |
| 256 | + cmd = "adb shell dumpsys battery set status 1" |
| 257 | + os.popen(cmd) |
| 258 | + while self.counter > 0: |
| 259 | + self.test_process() |
| 260 | + self.counter = self.counter - 1 |
| 261 | + # 每5秒采集一次数据, 真实测试场景建议在0.5-1小时 |
| 262 | + time.sleep(5) |
| 263 | +``` |
| 264 | + |
| 265 | +### 内存 |
| 266 | + |
| 267 | +##### 获取内存 |
| 268 | + |
| 269 | +```shell |
| 270 | +adb shell top |
| 271 | +# -d 刷新频率, 1 代表多久刷新一次,单位秒 |
| 272 | +adb shell top -d 1 |
| 273 | +# 输出到指定文件,测试完终止命令就可以分析指定文件 |
| 274 | +adb shell top -d 1 > meminfo |
| 275 | +# 筛选指定包名,进行分析, windows上可以用type代替cat, findstr代替grep |
| 276 | +cat meminfo | grep packagename |
| 277 | +``` |
| 278 | + |
| 279 | +> VSS - Virtual Set Size 虚拟消耗内存 |
| 280 | +> |
| 281 | +> RSS - Resident Set Size 实际使用物理内存 |
| 282 | +
|
| 283 | +##### 脚本实现 |
| 284 | + |
| 285 | +脚本负责对命令行中测试后生成的meminfo文件进行分析,然后生成分析数据到csv文件,然后可以利用该csv文件进行图表绘制,内存数据获取时,建议测试时间长一点,方便分析使用过程中内存数据是否稳定,vss和rss分别分析。 |
| 286 | + |
| 287 | +```python |
| 288 | +# 控制类 |
| 289 | +class Controller(object): |
| 290 | + def __init__(self): |
| 291 | + # 定义收集数据的数组 |
| 292 | + self.all_data = [("id", "vss", "rss")] |
| 293 | + |
| 294 | + # 分析数据 |
| 295 | + def analyze_data(self): |
| 296 | + content = self.read_file() |
| 297 | + i = 0 |
| 298 | + for line in content: |
| 299 | + if "org.chromium.webview_shell" in line: |
| 300 | + print line |
| 301 | + line = "#".join(line.split()) |
| 302 | + # 角标7和8不是固定的,要看你生成的meminfo文件里vss和rss出现的位置来确定 |
| 303 | + vss = line.split("#")[7].strip("K") |
| 304 | + rss = line.split("#")[8].strip("K") |
| 305 | + |
| 306 | + # 将获取到的数据存到数组中 |
| 307 | + self.all_data.append((i, vss, rss)) |
| 308 | + i = i + 1 |
| 309 | + |
| 310 | + # 读取数据文件 |
| 311 | + @staticmethod |
| 312 | + def read_file(): |
| 313 | + mem_info = file("meminfo", "r") |
| 314 | + content = mem_info.readlines() |
| 315 | + mem_info.close() |
| 316 | + return content |
| 317 | + |
| 318 | + # 数据的存储 |
| 319 | + def save_data_to_csv(self): |
| 320 | + csv_file = file('meminfo.csv', 'wb') |
| 321 | + writer = csv.writer(csv_file) |
| 322 | + writer.writerows(self.all_data) |
| 323 | + csv_file.close() |
| 324 | + |
| 325 | + |
| 326 | +if __name__ == '__main__': |
| 327 | + controller = Controller() |
| 328 | + controller.analyze_data() |
| 329 | + controller.save_data_to_csv() |
| 330 | +``` |
| 331 | + |
| 332 | +### FPS&过度渲染 |
| 333 | + |
| 334 | +##### FPS |
| 335 | + |
| 336 | +frames per second - 每秒的帧数 |
| 337 | + |
| 338 | +> Android中每一帧的绘制时间大于16秒,则可能会产生卡顿的现象,可以借助设置-开发者选项-GPU呈现模式分析,选择在屏幕上呈现为条形图,屏幕中横着的绿线就是16ms的基准线,高于绿线的条形图就是发生卡顿的帧 |
| 339 | +
|
| 340 | +##### 过度渲染 |
148 | 341 |
|
| 342 | +描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次 |
149 | 343 |
|
| 344 | +> 可以借助设置-开发者选项-调试GPU过度绘制-选择显示过度绘制区域,从最优到最差:蓝,绿,淡红,红。 |
0 commit comments