我是组织的一块砖,哪里需要哪里搬~~~
负责Team内自动化测试的第三个月,记录一下最近工作中遇到的一些问题及解决方式。
公司产品为某机器人项目板卡,Ubantu系统,自动化测试主要针对系统软件在各场景下长时间运行的稳定性/并发交互运行稳定性测试,测试框架以Python为主,偶尔使用shell辅助测试。
最近在系统重启稳定性方面遇到了一些问题。
Talk is cheap,show me the code:
...
result = False # result默认值为False
if "device" in adb.run_cmd("adb get-state"): # 重启前,预期为可获取到device
result_before_reboot = True
else:
result_before_reboot = False
if "device" not in adb.run_cmd("adb get-state"): # 重启中,预期为不可获取到device
result_during_reboot = True
else:
result_during_reboot = False
adb.run_cmd("adb wait-for-device")
if "device" in adb.run_cmd("adb get-state"): # 重启后,预期为可获取到device
result_after_reboot = True
else:
result_after_reboot = False
if result_before_reboot and result_during_reboot and result_after_reboot: # 三次判断同时为True时,result为True
result = True
else:
Print.error("Reboot device failed.")
return result
...
以上为重启脚本的大致流程,此前reboot没有出现过问题,但最近发现,存在两次测试结果的时间差长达三小时之久的现象,即下午一点进行第100次测试并得出结果为pass,随后进行第101次测试,在下午四点的时候第101次测试结束,结果为pass。期间历时三小时之久,只完成了一次reboot,且判断结果为pass。显然这是不正常的,check后发现,reboot测试一段时间后,reboot command下发后,device并没有立即响应,而是经过很长一段时间后,才进行reboot动作。
为捕获这一异常,修改脚本中的
...
adb.run_cmd("adb wait-for-device")
...
该命令会导致下发reboot command后,如果device 在reboot后一直没起来,或者很长时间才起来,脚本会一直等待到device启动成功为止。将该行指令替换为:
sleep(30)
不再无休止等待,舔狗也需要有春天~~此处等待时间视痴情成程度而定。。。
从此解决了痴儿千年等一回的异常。
新的挑战还在继续。
在某次分析log的过程中,我们发现,adb reboot后,adb get-state没有return device,此时我们判断result_during_reboot为True,但其实device只是进入了某不知名状态,随后退出该状态,没有真正进行reboot(浅尝辄止,假装自己已经reboot过了,贼机智,手动狗头)。
你伪装得如此自然,我却看不见?此时引入另一个判断:
class Reboot(Product_Reboot):
_systemd_pid = None
@staticmethod
def adb_shell_reboot_randomly():
def systemd_pid_check():
pid_changed = False
pid_result = adb.run_cmd("adb shell \"ps -ef | grep servicemanager | grep -v grep\"")
for line in pid_result.split("\n\n"):
if line:
for re_result in re.compile(r'\d+').finditer(line):
current_systemd_pid = re_result.group()
if current_systemd_pid != Reboot._systemd_pid:
Print.info("servicemanager pid was changed!")
Reboot._systemd_pid = current_systemd_pid
pid_changed = True
Print.info("servicemanager pid is : {}".format(Reboot._systemd_pid))
break
return pid_changed
关于servicemanager,大神们的文章写的很详细了,此处不再赘述,传送门在此。
我们只需要知道,开发小哥哥告诉我们的,每次重启之后,servicemanager pid肯定会发生改变,可以通过它来判断系统是真的重启了还是只是打了个盹儿?
...
result_during_reboot = systemd_pid_check()
...
if result_before_reboot and result_during_reboot:
result = True
Print.info("Randomly adb shell reboot device successfully.")
else:
Print.error("Randomly adb shell reboot device failed.")
return result
...
此次修改之后,测试过程中fail的次数确实多了许多,但是最后check发现,很多fail其实系统却是reboot成功的,只是servicemanager pid没有发生改变而已(人家真的冤枉嘛…)
此次修改造成了测试结果统计时工作量的增加,许多fail需要一次次的检查每一次fail的原因,发现都是pid未改变,但是分析其他log发现系统是真的被冤枉了~这其实已经影响了测试结果的可靠程度,造成了随后两个星期内,reboot测试fail的问题,开发小哥统一回复:真的重启了,只是pid未改变而已(而我竟无法反驳?)。
在心惊胆颤的输出两个星期reboot测试报告一路绿灯后,因一直存在reboot fail,恐软件真的存在问题而误判没有暴露出来bug,我引入了下面的判断:
...
def system_uptime_check():
check_uptime = False
uptime = adb.run_cmd("adb shell uptime")
print("uptime = {}".format(uptime))
if uptime < 3:
print("uptime is less than 3")
check_uptime = True
else:
print("uptime is more than 3")
return False
return check_uptime
在reboot case中,加入system_check_uptime,最后执行判断
...
if result_before_reboot and result_during_reboot and system_uptime_check:
result = True
Print.info("Randomly adb shell reboot device successfully.")
else:
Print.error("Randomly adb shell reboot device failed.")
return result
...
从此,开发小哥不再喊冤~~~
自动化测试过程中,会遇到很多类似的问题,reboot只是相对非常简单的一条case,在实际的测试过程中,自动化测试脚本的开发,要尽量做到使用最简单直接的判断,这就要求测试工程师必须对自身业务逻辑理解非常透彻,场景设计永远是测试工程师最核心的竞争力。
以上。