0.说明:
演示均为真机,不是模拟器
软件自行安装
1.框架结构
- 业务功能的封装
- 测试用例封装
- 测试包管理
- 截图处理
- 断言处理
- 日志获取
- 测试报告生成
- 数据驱动
- 数据配置
2.代码搭建
driver配置封装
lyf_caps.yaml 配置表
desired_caps.py
import yaml
import logging.config
from appium import webdriver
import os
CON_LOG = '../config/log.conf'
logging.config.fileConfig(CON_LOG)
logging = logging.getLogger()
def appium_desired():
with open('../config/lyf_caps.yaml','r',encoding='utf-8') as file:
data = yaml.load(file)
desired_caps={}
desired_caps['platformName']=data['platformName']
desired_caps['platformVersion']=data['platformVersion']
desired_caps['deviceName']=data['deviceName']
base_dir = os.path.dirname(os.path.dirname(__file__))
app_path = os.path.join(base_dir, 'app', data['appname'])
desired_caps['app'] = app_path
desired_caps['noReset']=data['noReset']
desired_caps['unicodeKeyboard']=data['unicodeKeyboard']
desired_caps['resetKeyboard']=data['resetKeyboard']
desired_caps['appPackage']=data['appPackage']
desired_caps['appActivity']=data['appActivity']
logging.info('start run app...')
driver = webdriver.Remote('http://'+str(data['ip'])+':'+str(data['port'])+'/wd/hub', desired_caps)
driver.implicitly_wait(5)
return driver
基类封装
baseView.py
common公共模块封装
公共方法封装 : common_fun.py
from baseView.baseView import BaseView
from common.desired_caps import appium_desired
from selenium.common.exceptions import NoSuchElementException
import logging.config
from selenium.webdriver.common.by import By
import os
import time
import csv
class Common(BaseView):
# 取消升级和跳过引导按钮
cancel_upgradeBtn = (By.ID, 'android:id/button2')
skipBtn = (By.ID, 'com.tal.lyf:id/tv_skip')
# 登录后浮窗广告取消按钮
wemedia_cacel = (By.ID, 'com.tal.lyf:id/view_wemedia_cacel')
def check_updateBtn(self):
logging.info("============check_updateBtn===============")
try:
element = self.driver.find_element(*self.cancel_upgradeBtn)
except NoSuchElementException:
logging.info('update element is not found!')
else:
logging.info('click cancelBtn')
element.click()
def check_skipBtn(self):
logging.info("==========check_skipBtn===========")
try:
element = self.driver.find_element(*self.skipBtn)
except NoSuchElementException:
logging.info('skipBtn element is not found!')
else:
logging.info('click skipBtn')
element.click()
def get_screenSize(self):
'''
获取屏幕尺寸
:return:
'''
x = self.get_window_size()['width']
y = self.get_window_size()['height']
return (x, y)
def swipeLeft(self):
logging.info('swipeLeft')
l = self.get_screenSize()
y1 = int(l[1] * 0.5)
x1 = int(l[0] * 0.95)
x2 = int(l[0] * 0.25)
self.swipe(x1, y1, x2, y1, 1000)
def getTime(self):
self.now = time.strftime("%Y-%m-%d %H_%M_%S")
return self.now
def getScreenShot(self, module):
time = self.getTime()
image_file = os.path.dirname(os.path.dirname(__file__)) + '/screenshots/%s_%s.png' % (module, time)
logging.info('get %s screenshot' % module)
self.driver.get_screenshot_as_file(image_file)
def check_market_ad(self):
'''检测登录或者注册之后的界面浮窗广告'''
logging.info('=======check_market_ad=============')
try:
element = self.driver.find_element(*self.wemedia_cacel)
except NoSuchElementException:
pass
else:
logging.info('close market ad')
element.click()
def get_csv_data(self, csv_file, line):
'''
获取csv文件指定行的数据
:param csv_file: csv文件路径
:param line: 数据行数
:return:
'''
with open(csv_file, 'r', encoding='utf-8-sig') as file:
reader = csv.reader(file)
for index, row in enumerate(reader, 1):
if index == line:
return row
业务模块封装
1.登录页面业务逻辑模块
loginView.py
import logging
from common.desired_caps import appium_desired
from common.common_func import Common, By
from selenium.common.exceptions import NoSuchElementException
class LoginView(Common):
# 登录界面元素
username_type = (By.ID, 'com.tal.lyf:id/login_email_edittext')
password_type = (By.ID, 'com.tal.lyf:id/login_password_edittext')
loginBtn = (By.ID, 'com.tal.lyf:id/login_login_btn')
# 个人中心元素
username = (By.ID, 'com.tal.lyf:id/activity_usercenter_username')
button_myself = (By.ID, 'com.tal.lyf:id/mainactivity_button_mysefl')
# 个人中心下线警告提醒确定按钮
commitBtn = (By.ID, 'com.tal.lyf:id/tip_commit')
# 退出操作相关元素
settingBtn = (By.ID, 'com.tal.lyf:id/myapptitle_RightButtonWraper')
logoutBtn = (By.ID, 'com.tal.lyf:id/setting_logout_text')
tip_commit = (By.ID, 'com.tal.lyf:id/tip_commit')
def login_action(self, username, password):
self.check_updateBtn()
self.check_skipBtn()
logging.info('============login_action==============')
logging.info('username is:%s' % username)
self.driver.find_element(*self.username_type).send_keys(username)
logging.info('password is:%s' % password)
self.driver.find_element(*self.password_type).send_keys(password)
logging.info('click loginBtn')
self.driver.find_element(*self.loginBtn).click()
logging.info('login finished!')
def check_account_alert(self):
'''检测账户登录后是否有账户下线提示'''
logging.info('====check_account_alert======')
try:
element = self.driver.find_element(*self.commitBtn)
except NoSuchElementException:
pass
else:
logging.info('click commitBtn')
element.click()
def check_loginStatus(self):
logging.info('==========check_loginStatus===========')
self.check_market_ad()
self.check_account_alert()
try:
self.driver.find_element(*self.button_myself).click()
self.driver.find_element(*self.username)
except NoSuchElementException:
logging.error('login Fail!')
self.getScreenShot('login Fail')
return False
else:
logging.info('login success!')
l.logout_action()
return True
def logout_action(self):
logging.info('=========logout_action==========')
self.driver.find_element(*self.settingBtn).click()
self.driver.find_element(*self.logoutBtn).click()
self.driver.find_element(*self.tip_commit).click()
注册页面业务逻辑封装
registerView.py
主页页面业务逻辑封装
myHomeView.py
订单页面业务逻辑封装
orderView.py
退出页面业务逻辑封装
quitView.py
骑手页面业务逻辑封装
riderView.py
门店页面业务逻辑封装
shopView.py
...自行封装 哈哈哈哈
config文件配置
日志文件配置 log.config
[loggers] keys=root,infoLogger [logger_root] level=DEBUG handlers=consoleHandler,fileHandler [logger_infoLogger] handlers=consoleHandler,fileHandler qualname=infoLogger propagate=0 [handlers] keys=consoleHandler,fileHandler [handler_consoleHandler] class=StreamHandler level=INFO formatter=form02 args=(sys.stderr,) [handler_fileHandler] class=FileHandler level=INFO formatter=form01 args=('../logs/mylog.log', 'a') [formatters] keys=form01,form02 [formatter_form01] format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s [formatter_form02] format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
测试用例封装
1.测试用例执行开始结束操作封装myunit.py
2.注册用例:test_register.py
3.登录用例
test_login.py
from common.myunit import StartEnd
from businessView.loginView import LoginView
import unittest
import logging
class LoginTest(StartEnd):
csv_file = '../data/account.csv'
# @unittest.skip("test_login_zzzz")
def test_login_zxw2017(self):
logging.info('==========test_login_zzzz========')
l=LoginView(self.driver)
data = l.get_csv_data(self.csv_file,1)
l.login_action(data[0],data[1])
self.assertTrue(l.check_loginStatus())
# @unittest.skip('skip test_login_yyyy')
def test_login_zxw2018(self):
logging.info('=========test_login_yyyy============')
l=LoginView(self.driver)
data = l.get_csv_data(self.csv_file,2)
l.login_action(data[0],data[1])
self.assertTrue(l.check_loginStatus())
# @unittest.skip("test_login_erro")
def test_login_erro(self):
logging.info('=======test_login_erro=========')
l=LoginView(self.driver)
data = l.get_csv_data(self.csv_file, 3)
l.login_action(data[0], data[1])
self.assertTrue(l.check_loginStatus(),msg='login fail!')
4.其他模块用例自行编写
执行测试用例&报告生成
后续可结合jenkins持续集成运行。
附录架构说明