继续完善上篇的小工具功能,增加以下功能
a、增加关于作者信息标签
b、增加跑Monkey功能
c、增加日志输出和文件保存路径选择
一、先看下效果
二、实例代码
代码语言:javascript复制# coding:utf-8
from tkinter import *
from datetime import datetime
from tkinter import messagebox
import time,os
import threading
import tkinter as tk
from tkinter import filedialog, dialog
class MonkeyTest:
def __init__(self):
self.root = Tk()
self.root.title('APP测试小工具 V1.0')
self.line = 1 # 用于统计monkey日志的行数
self.flagWhile = 1 # 循环判断标志位
def getPacky(self):
# adb shell dumpsys window w |findstr / |findstr name=
zhi = (os.popen('adb shell dumpsys window w |findstr / |findstr name=').read())
d = (zhi.strip().split('n'))
pack = d[0].split('=')[-1]
# print(pack)
result = pack.split('/')[0]
# print(result)
self.entryPkg.delete(0, END) # 清空设备id编辑框
self.entryPkg.insert(7, result) # 填写包名
def get_Activity(self):
zhi = (os.popen('adb shell dumpsys window w |findstr / |findstr name=').read())
d = (zhi.strip().split('n'))
act = d[0].split('=')[-1]
print(act)
activity = act.split('/')[1]
print(activity)
result = activity.replace(')', '')
# print(result)
self.entryAct.delete(0, END) # 清空编辑框
self.entryAct.insert(8, result) # 填写Act
def createRun(self):
"""开始运行"""
# self.frame = Frame()
self.frame = tk.LabelFrame(self.root, text="Monkey测试", font=('微软雅黑', 20))
self.frame.pack()
self.create_menu()
rowIsANR, rowPackage, rowAct, rowRemind, rowExecute, rowInfo = 6, 7, 8, 9, 10, 11
padxLabel, padyLabel = 5, 10
padxEntry, padyEntry = 20, 20
padxButton, padyButton = 10, 20
padxListbox, padyListbox = 10, 10
# 设备ID
btnDevice = Button(self.frame, text='获取设备ID', command=self.getDeivceID)
btnDevice.grid(row=0, column=0, sticky=E, padx=padxLabel, pady=padyLabel)
self.entryDevice = Entry(self.frame)
self.entryDevice.grid(row=0, column=1, sticky=W, padx=padxEntry)
# 包名
btnPkg = Button(self.frame, text='获取包名', command=self.getPacky)
btnPkg.grid(row=1, column=0, sticky=E, padx=padxLabel, pady=padyLabel)
self.entryPkg = Entry(self.frame)
self.entryPkg.grid(row=1, column=1, sticky=W, padx=padxEntry)
# Activity
btnAct = Button(self.frame, text='获取Activity', command=self.get_Activity)
btnAct.grid(row=2, column=0, sticky=E, padx=padxLabel, pady=padyLabel)
self.entryAct = Entry(self.frame)
self.entryAct.grid(row=2, column=1, sticky=W, padx=padxEntry)
# crash
labelCrash = Label(self.frame, text='出现crash是否继续:')
labelCrash.grid(row=3, column=0, sticky=E, padx=padxLabel, pady=padyLabel)
self.vCrash = IntVar()
btnCrash = Checkbutton(self.frame, variable=self.vCrash)
btnCrash.select() # 默认勾选
btnCrash.grid(row=3, column=1, sticky=W, padx=padxButton)
# ANR
labelANR = Label(self.frame, text='出现ANR是否继续:')
labelANR.grid(row=3, column=2, sticky=E, padx=padxLabel, pady=padyLabel)
self.vANR = IntVar()
btnANR = Checkbutton(self.frame, variable=self.vANR)
btnANR.select() # 默认勾选
btnANR.grid(row=3, column=3, sticky=W, padx=padxButton)
# 事件次数
labelEvent = Label(self.frame, text='事件次数:')
labelEvent.grid(row=0, column=2, sticky=W, padx=padxLabel, pady=padyLabel)
self.entryEvent = Entry(self.frame)
self.entryEvent.grid(row=0, column=3, sticky=E, padx=padxEntry)
# seed值
labelSeed = Label(self.frame, text='seed值:')
labelSeed.grid(row=1, column=2, sticky=W, padx=padxLabel, pady=padyLabel)
self.entrySeed = Entry(self.frame)
self.entrySeed.grid(row=1, column=3, sticky=E, padx=padxEntry)
# 提示信息
self.labelRemind = Label(self.frame, fg='red', font=('微软雅黑'))
self.labelRemind.grid(row=rowRemind, column=0, columnspan=2, sticky=E W, padx=padxLabel, pady=padyLabel)
# 执行
self.btnExecute = Button(self.frame, text=' 执行 ', command=self.execute)
self.btnExecute.grid(row=rowExecute, column=0, sticky=E, padx=padxButton)
# 停止
btnStop = Button(self.frame, text=' 停止 ', command=self.stop)
btnStop.grid(row=rowExecute, column=1, sticky=W, padx=padxButton)
# 展示信息
self.listInfo = Listbox(self.frame, width=70, height=10)
self.listInfo.grid(row=rowInfo, column=0, columnspan=2, padx=padxListbox, pady=padyListbox)
self.root.mainloop()
def getDeivceID(self):
'''
获取设备id
:return:
'''
cmd = 'adb devices >c:/devices.log'
os.system(cmd)
with open('c:/devices.log','r') as f:
result = f.readlines()[1].split('t')[0]
self.entryDevice.delete(0, END) # 清空设备id编辑框
self.entryDevice.insert(0, result) # 填写设备id
def execute(self):
# 设备id不为空,运行脚本时其实没有限定设备id,此项主要用来检测是否能运行adb
if len(self.entryDevice.get().strip()) == 0:
self.labelRemind['text'] = '请输入设备ID'
return
# 事件次数为数字
self.event = self.entryEvent.get().strip()
if not self.event.isdigit():
self.labelRemind['text'] = '请输入正确的次数'
return
# seed值为数字
self.seed = self.entrySeed.get().strip()
if not self.seed.isdigit():
self.labelRemind['text'] = '请输入正确的seed'
return
# 是否忽略crash
self.crash = '--ignore-crashes'
if self.vCrash.get() == 0:
self.crash = ''
# 是否忽略ANR
self.anr = '--ignore-timeouts'
if self.vANR.get() == 0:
self.anr = ''
# 包名不为空
self.pkg = self.entryPkg.get().strip()
if len(self.pkg) == 0:
self.labelRemind['text'] = '需要填写测试的包名'
return
# 按钮置灰
self.btnExecute['state'] = 'disabled'
lTime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.listInfo.insert(END, lTime ' Monkey测试开始。。。')
# 重置提示语
self.labelRemind['text'] = ''
# 重置行数
self.line = 1
# 重置循环标志位
self.flagWhile = 1
# 运行monkey语句
t1 = threading.Thread(target=self.executeCmd)
t1.start()
# 显示monkey日志
t2 = threading.Thread(target=self.startReadLog)
t2.start()
def executeCmd(self):
cmd = 'adb shell monkey -p ' self.pkg ' ' self.crash ' ' self.anr ' --monitor-native-crashes --throttle 1000 -s ' self.seed ' -v -v -v ' self.event ' >c:/monkey.log'
os.system(cmd)
def startReadLog(self):
'''
5秒读一次monkey的log,
第一次等5秒是让adb命令先运行,防止先读log而又没有monkey.log文件,导致异常
:return:
'''
while self.flagWhile > 0: # 标志位初始值大于0,进入循环
time.sleep(5)
self.readLog()
def stop(self):
self.btnExecute['state'] = 'active' # 激活执行按钮
self.flagWhile = -1 # 标志位小于0,跳出循环
def readLog(self):
count = 1
f = open('c:/monkey.log', 'r', encoding='utf8')
for i in f.readlines():
count = count 1 # 记录每次读取log的行数,每读一行,计数 1
# count > line 防止重复insret
if count > self.line and ('// CRASH:' in i or 'ANR in ' in i):
lTime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.listInfo.insert(END, lTime ' ' i)
# 存在'// Monkey finished',就判断monkey结束
elif '// Monkey finished' in i:
lTime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.listInfo.insert(END, lTime ' Monkey测试结束!')
self.stop()
# print(self.line, count)
self.line = count
def create_menu(self):
# 创建一个下拉菜单“文件”,然后将它添加到顶级菜单中
MenuBar = tk.Menu(self.root)
# 将菜单栏放到主窗口
self.root.config(menu=MenuBar)
# 创建文件菜单,不显示分窗
fileBar = tk.Menu(MenuBar, tearoff=0)
# 添加文件菜单项
fileBar.add_command(label="Open File", command=self.open_file)
fileBar.add_command(label="Save File", command=self.save_file)
# 创建分割线
fileBar.add_separator()
fileBar.add_command(label="exit", command=self.root.quit)
# 将文件菜单添加到菜单栏
MenuBar.add_cascade(label="File", menu=fileBar)
helpmenu = Menu(MenuBar, tearoff=0)
helpmenu.add_command(label="About", command=self.getAbout)
MenuBar.add_cascade(label="Help", menu=helpmenu)
def open_file(self):
'''
打开文件
:return:
'''
global file_path
global file_text
file_path = filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser('H:/')))
print('打开文件:', file_path)
if file_path is not None:
with open(file=file_path, mode='r ', encoding='utf-8') as file:
file_text = file.read()
self.listInfo.insert('insert', file_text)
def save_file(self):
global file_path
global file_text
file_path = filedialog.asksaveasfilename(title=u'保存文件')
print('保存文件:', file_path)
# file_text = text1.get('1.0', tk.END)
if file_path is not None:
with open(file=file_path, mode='a ', encoding='utf-8') as file:
file.write(file_text)
# text1.delete('1.0', tk.END)
dialog.Dialog(None, {'title': '是否关闭弹框', 'text': '保存完成', 'bitmap': 'warning', 'default': 0,
'strings': ('确定', '取消')})
print('保存完成')
def getAbout(self):
messagebox.showinfo(title='about Author', message=u'工具使用说明:n 1:快速获取设备ID、应用包名和Activity;n '
u'2:执行Monkey测试,可设定日志保存路径;n 3:欢迎关注公众号【自学测试之道】')
m = MonkeyTest()
m.createRun()
后续可以根据自己的工作情况,逐步完善测试工具,当然,学习还是要持续进行的