APP UI自动化测试同样可以使用unittest框架,与web的UI自动化类似
整个自动化流程介绍
1) 会先从手工用例里面抽离出要做自动化的用例,在测试用例里面会加一个执行方式的标签,标明是手动还是自动化,以此明确自动化测试的范围。
2) 开始搭建自动化测试框架,整个框架的设计是基于Python+appium+一些模块的封装。我们封装的模块分几部分内容:
- case层:是核心,放自动化用例。case层的设计原理是:使用了unittest三部分内容,setup、teardown和test方法。
- setup是做初始化的一些操作,初始化一些参数设置、APP启动,还会加一个启动时间。
- Teardown是做一些退出、截图,打印结束时间的操作。
- Test方法是手工用例对应的自动化用例
- report层:放HTML testrunner,一个生成HTML报告的py文件,最终的自动化测试报告也会生成在这个模块下
- public层:比如登录以及经常要业务复用的一些场景,会将它们抽离出来作为public,在其他的case层可以直接调用
- testrunner:在case层里面有很多自动化用例,不可能一个一个去运行。所以写了这个testrunner,通过它可以实现批量运行,运行case层里面所有的py文件。这样的好处是,对于测试回归来说,在这个版本提交之后,每天都可以进行一次回归,回归之后可以查看报告,然后对有错误的地方进行分析,看是否对老功能有影响。
1. 初始化代码详解
from appium import webdriver
desired_caps = {} #定义了一个字典,下面是字典里面的值
desired_caps['platformName'] = 'android' #平台名称,如果是苹果,则写ios(小写)
desired_caps['platformVersion'] = '5.1' #手机系统版本号,与测试手机版本一致
desired_caps['deviceName'] = 'Android Emulator' #设备名,appium不强制检查此参数值,只要有值即可
desired_caps['noReset'] = 'True' #退出APP时,不重置APP的数据
desired_caps['appPackage'] = 'cn.xiaochuankeji.tieba' #包名,每个APP就是通过包名来唯一区分
desired_caps['appActivity'] = '.ui.base.SplashActivity' #首个界面的activity
driver = webdriver.Remote('http://localhost:4723/wd/hub',desired_caps) #初始化driver
#http://localhost:4723/wd/hub是远程的请求地址,前面是域名,/wd/hub是路径 desired_caps是参数
#4723是端口号,需要与appium监听的端口号对应(在appium首页可以设置端口号)
- 界面名称:每一个界面就是一个activity(web是通过URL来区分界面,APP是通过activity区分界面)
- activity可能是复用的:在APP中,有些布局是类似的时候,可能activity是一样的
包名获取方法:
APP打开,在cmd中输入adb shell dumpsys activity top|findstr “ACTIVITY”
/前面是包名,/后面以点号开始的一串是当前界面的activity名称
初始化时,只能进到APP首个界面
获取首个界面activity的方法:先在cmd中将获取命令输好,再启动APP,APP起来之后,马上在命令窗口点回车(如果点慢了,可能就不是首个界面了)
初始化时,appium会给手机里安装2个APP:
- appiumSettings:appium设置的东西,自动安装
- Unlock:手机解锁,解不了图文和密码的,只能滑动解锁
2. 框架介绍
2.1 Public
public封装公用业务模块,如APP登录
封装一个Mylogin类,类里面是对应的login方法
如封装的登录模块:
import time
class Mylogin(object):
def __init__(self, driver):
self.driver = driver
def login(self):
self.driver.implicitly_wait(60)
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/me_item").click()
time.sleep(2)
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/tv_notLogin_goLogin").click()
time.sleep(1)
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/login_mode").click()
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/phone_num_edit").send_keys("151********")
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/code_edit").send_keys("a123456")
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/login").click()
time.sleep(5)
2.2 report
放一个HTML testrunner.py文件,自动生成报告
2.3 case(核心)
- APP和web有一些共有的,所以在case层下分了APP和web。
- setup:初始化
- teardown:清理
- test方法:每一个test方法对应一条手工用例,每个test方法都需要以test开头,不然不会执行。
2.4 几种典型case例子
1.有时进入首页时会弹出青少年模式,有时不会弹出。对于这种情况,如果需要定位首页控件,可以使用try语句
def testshouye01_01(self):
'''验证首页导航栏文案显示是否正常'''
time.sleep(8)
try:
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/home_item").click()
except:
pass
time.sleep(6)
navText = self.driver.find_elements_by_id("cn.xiaochuankeji.tieba:id/title")
self.assertEqual(navText[0].text, "关注")
self.assertEqual(navText[1].text, "推荐")
self.assertEqual(navText[2].text, "视频")
self.assertEqual(navText[3].text, "图文")
2.动态内容处理:验证帖子列表内容跳转
def testshouye01_02(self):
'''验证帖子列表内容跳转'''
time.sleep(8)
aa = self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/expand_content_view")
bb = aa.text
aa.click()
time.sleep(3)
forumDetailText = self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/tvTitle")
cc = self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ss")
self.assertEqual(forumDetailText.text,"帖子详情")
self.assertEqual(bb,cc.text)
3.验证评论帖子功能
def testshouye01_03(self):
'''验证评论帖子功能'''
Mylogin(self.driver).login()
time.sleep(3)
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/iconTabItem").click() #点击首页
time.sleep(6)
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/expand_content_view").click() #点击帖子列表中的一个数据
time.sleep(3)
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/etInput").send_keys("textCESHI") #输入评论内容
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/send").click() #点击发送
sendContent = self.driver.find_elements_by_id("cn.xiaochuankeji.tieba:id/expandTextView") #将所有评论内容的控件全部拿到
sendContentRawList = [] #定义列表 ['a123456','猫']
for i in range(0, len(sendContent)): #循环所有控件
sendContentRawList.append(sendContent[i].text) #将控件上的文本信息全部追加到定义的列表中
sendContentList = "".join(sendContentRawList) #将列表转换成一个字符串 "a123456猫"
self.assertIn("textCESHI", sendContentList) #断言:如果评论内容在所有评论内容里面,说明评论内容已经显示出来了
#测试时,需要让评论内容唯一化,可以加时间实现,text+时间(精确到秒)
4.页面滑动,直到找到某一控件为止
def testshouye01_04(self):
'''验证关注功能'''
time.sleep(10)
while True:
try:
self.driver.find_element_by_id("cn.xiaochuankeji.tieba:id/v_epaulet_follow").click()
break
except:
height = self.driver.get_window_size()['height']
width = self.driver.get_window_size()['width']
self.driver.swipe(width * 0.5, height * 0.8, width * 0.5, height * 0.2, 1000) # 当关注没有显示时,上滑
#断言
toast = ("xpath", '//*[contains(@text,"关注成功")]')
# 最大等待时间10秒,每隔0.1秒检测1次,直到当前界面存在了关注成功提示
ele = WebDriverWait(self.driver, 10, 0.1).until(EC.presence_of_element_located(toast))
self.assertEqual("关注成功",ele.text)