pageobject分级设计模式的思路
将一些公共的模块抽离出来
将元素定位方法和元素属性与业务代码分离
将功能模块封装成一个个独立的单元模块
使用unittest框架进行用例的综合管理
pageobject的目录结构
common里的disired_caps公共模块
from selenium import webdriver
from appium import webdriver
import yaml
import logging
import logging.config
import os
CON_LOG = '../config/log.conf'
logging.config.fileConfig(CON_LOG)
logging = logging.getLogger()
def appium_disired():
with open('../config/kyb_caps.yaml', 'r', encoding='utf-8') as file:
data = yaml.load(file, Loader=yaml.FullLoader)
#解决文件没有被释放的问题
base_path = os.path.dirname(os.path.dirname(__file__))
app_path = os.path.join(base_path, 'app', data['appname'])
desired_caps = {}
desired_caps['platformName'] = data['platformName'] # android的apk还是IOS的ipa
desired_caps['platformVersion'] = data['platformVersion'] # android系统的版本号
desired_caps['deviceName'] = data['deviceName'] # 手机设备名称,通过adb devices 查看
desired_caps['app'] = app_path
desired_caps['appPackage'] = data['appPackage'] # apk的包名
desired_caps['appActivity'] = data['appActivity'] # apk的launcherActivity
# 不需要再次签名
desired_caps['noSign'] = data['noSign']
# 不需要清理数据,避免重新安装的问题
desired_caps['noReset'] = data['noReset']
# desired_caps['unicodeKeyboard'] = True #使用unicodeKeyboard的编码方式来发送字符串,中文方式
# desired_caps['resetKeyboard'] = True #将键盘给隐藏起来
driver = webdriver.Remote('http://' + str(data['ip']) + ':' + str(data['port']) + '/wd/hub', desired_caps)
logging.info('caps ready')
return driver
if __name__ == '__main__':
appium_disired()
baseView模块,包含driver初始化,定位元素等
class BaseView(object):
def __init__(self, driver):
self.driver = driver
def find_element(self, *loc):
return self.driver.find_element(*loc)
def find_elements(self,*loc):
return self.driver.find_elements(*loc)
def get_window_size(self):
return self.driver.get_window_size()
def swipe(self,start_x, start_y, end_x, end_y, duration):
return self.driver.swipe(start_x, start_y, end_x, end_y, duration)
common模块,有如检查元素的方法,左右滑动,截图等方法
import logging
from baseView.baseView import BaseView
from common.disired_caps import appium_disired
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
import time
import os
import csv
class Common(BaseView):
cancelBtn = (By.ID, 'android:id/button2')
skipBtn = (By.ID, 'com.tal.kaoyan:id/tv_skip')
wemedia_cacel = (By.ID, 'com.tal.kaoyan:id/view_wemedia_cacel')
def check_cancelBtn(self):
try:
cancelBtn = self.driver.find_element(*self.cancelBtn)
except NoSuchElementException:
logging.info('no element')
else:
cancelBtn.click()
def check_skipBtn(self):
try:
skipBtn = self.driver.find_element(*self.skipBtn)
except NoSuchElementException:
logging.info('no element')
else:
skipBtn.click()
def get_size(self):
x = self.driver.get_window_size()['width']
y = self.driver.get_window_size()['height']
return x, y
def swipeLeft(self):
l =self.get_size()
x1 = int(l[0] * 0.9)
y1 = int(l[1] * 0.5)
x2 = int(l[0] * 0.1)
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_marcket_ad(self):
logging.info('check_market_ad')
try:
element = self.driver.find_element(self.wemedia_cacel)
except NoSuchElementException:
pass
else:
element.click()
if __name__ == '__main__':
driver = appium_disired()
com = Common(driver)
com.check_cancelBtn()
#com.check_skipBtn()
com.swipeLeft()
com.getScreenShot('startApp')
功能模块继承自common,里面有如登录过程,检查登录状态等用例可调用函数
from common.disired_caps import appium_disired
from common.Common import Common
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import logging
from collections import namedtuple
import re
from time import sleep
import csv
class LoginView(Common):
username_type = (By.ID, 'com.tal.kaoyan:id/login_email_edittext')
password_type = (By.ID, 'com.tal.kaoyan:id/login_password_edittext')
login_button = (By.ID, 'com.tal.kaoyan:id/login_login_btn')
tip_commit = (By.ID, 'com.tal.kaoyan:id/tip_commit')
button_mysefl = (By.ID, 'com.tal.kaoyan:id/mainactivity_button_mysefl')
username = (By.ID, 'com.tal.kaoyan:id/activity_usercenter_username')
RightButton = (By.ID, 'com.tal.kaoyan:id/myapptitle_RightButton_textview')
logoutButton = (By.ID, 'com.tal.kaoyan:id/setting_logout_text')
def login_action(self,username,password):
self.check_cancelBtn()
self.check_skipBtn()
self.driver.find_element(*self.username_type).send_keys(username)
self.driver.find_element(*self.password_type).send_keys(password)
self.driver.find_element(*self.login_button).click()
sleep(2)
def check_account_alert(self):
logging.info('=====check_account=====')
try:
element = self.driver.find_element(*self.tip_commit)
except NoSuchElementException:
pass
else:
logging.info('=====close tip_commit=====')
element.click()
def check_login_status(self):
logging.info('=====check_login_status====')
self.check_marcket_ad()
self.check_account_alert()
try:
button_mysefl = self.driver.find_element(*self.button_mysefl)
except NoSuchElementException:
pass
else:
logging.info('=====click_button_myself=====')
button_mysefl.click()
try:
element = self.driver.find_element(*self.username)
except NoSuchElementException:
logging.error('=======check_status_fail========')
self.driver.getScreenShot('login_fail')
return False
else:
logging.info('=====check_status_success=====')
self.logout_action()
return True
def logout_action(self):
logging.info('=====logout_action=====')
self.driver.find_element(*self.RightButton).click()
self.driver.find_element(*self.logoutButton).click()
self.driver.find_element(*self.tip_commit).click()
def get_csv_data(csv_file):
with open(csv_file, encoding='utf-8-sig') as file:
f_csv = csv.reader(file)
headings = next(f_csv)
# print(headings)
# for row in f_csv:
# print(row)
Row = namedtuple('Row', headings)
for r in f_csv:
row = Row(*r)
print(row.No) # 可直接通过row.Date等获取相应的元素
if(row.No == '1'):
print(row.username)
with open(csv_file, encoding='utf-8-sig') as f:
f_csv = csv.DictReader(f)
for row in f_csv:
print(row['No'])
if (row['No'] == '1'):
print(row['username'])
return
if __name__ == '__main__':
driver = appium_disired()
l = LoginView(driver)
l.login_action('15813384616', 'zhixue666666')
l.check_login_status()
# for i in range(4):
# get_csv_data('../data/account.csv')
使用unittest封装用例的StartEnd模块
unittest使用流程
定义StartEnd类继承unittest.TestCase,实现setUp和TearDown方法
import unittest
from common.Common import appium_disired
import logging
from time import sleep
class StartEnd(unittest.TestCase):
def setUp(self):
logging.info('start')
self.driver = appium_disired()
def tearDown(self):
logging.info('end')
sleep(5)
self.driver.close_app()
具体测试模块继承自StartEnd,进行数据驱动管理,从csv中读取用例,并测试返回值
from common.myunit import StartEnd
from business.loginView import LoginView
import logging
import unittest
#author aojaovie
class LoginTest(StartEnd):
csv_file = '../data/account.csv'
@unittest.skip("unitest_login_1")
def testlogin1(self):
logging.info('login test')
l = LoginView(self.driver)
data = l.get_csv_data(self.csv_file, 1)
l.login_action(data[0], data[1])
self.assertTrue(l.check_login_status())
@unittest.skip("unitest_login_2")
def testlogin2(self):
logging.info('login test')
l = LoginView(self.driver)
data = l.get_csv_data(self.csv_file, 2)
l.login_action(data[0], data[1])
self.assertTrue(l.check_login_status())
#@unittest.skip("unitest_login_error")
def testlogin3(self):
logging.info('login test')
l = LoginView(self.driver)
data = l.get_csv_data(self.csv_file, 3)
l.login_action(data[0], data[1])
self.assertTrue(l.check_login_status(), msg='login fail')
if __name__ == '__main__':
unittest.main()