(三)Python+unittest+selenium+ddt数据驱动_优化版
POM模式
四层结构:基础封装层、页面对象层、测试用例层、数据层
- 基础层:封装一些常用的方法,提高代码的复用。
(如:继承了selenium常用的webdriver操作,并对部分操作进行了封装; 封装日志功能;将所有界面共用的方法进行封装 等)(本次仅将 定位元素、等待元素显示、元素是否显示、点击、输入 等等作为基础层一些方法,对于其他,如日志功能,未加入进去,后续可以考虑优化) - 页面对象层:页面对象就是将每个界面当成一个对象,将界面中的元素当成对象的属性或者方法 (首页、多个不同pop框形式的登入页面)
- 测试用例层:uniittest框架来管理和执行用例 (此处:仅一个测试用例,即手机号码登入网易云账号)
- 数据层:传入的测试数据(账号,密码)
实例:
代码结构
1.基础层:
common.py
#coding=utf-8
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
class Common():
def __init__(self,driver):
self.driver = driver
def open_url(self,url):
self.driver.get(url)
def click(self,locator):
#self.find_element(locator).click()
self.driver.find_element(*locator).click()
def input_text(self,locator,text):
self.driver.find_element(*locator).send_keys(text)
def wait_for_element_displayed(self,locator,timeout=None,message=None):
return WebDriverWait(self.driver,10).until(lambda m:m.find_element(*locator).is_displayed(),message=message)
def is_element_displayed(self,locator,message=None):
try:
return self.driver.find_element(*locator).is_displayed
except Exception:
return False
def element_text(self,locator):
return self.driver.find_element(*locator).text
2.页面对象层
- page
- homePage.py
- scanOrOtherPage.py
- loginModePage.py
- phoneNumberLoginPage.py
- homePage.py,如下
#coding=utf-8
from pom.common.common import Common
from selenium.webdriver.common.by import By
class HomePage(Common):
_login_locator = (By.CSS_SELECTOR, 'a.link.s-fc3')
def __init__(self,driver):
self.driver = driver
def click_login(self,url):
self.open_url(url)
self.click(self._login_locator)
- scanOrOtherPage.py,如下:
#coding=utf-8
from pom.common.common import Common
from selenium.webdriver.common.by import By
class ScanOrOtherPage(Common):
_other_login_mode_locator =(By.CSS_SELECTOR ,'a.u-btn2.other')
def __init__(self,driver):
self.driver= driver
def select_other_login_mode(self):
self.click(self._other_login_mode_locator)
- loginModePage.py, 如下:
#coding=utf-8
from pom.common.common import Common
from selenium.webdriver.common.by import By
class LoginModePage(Common):
_privacy_policy_checkout_loactor = (By.CSS_SELECTOR ,'input#j-official-terms')
_phone_number_login_locator = (By.CSS_SELECTOR ,'a.u-btn2.u-btn2-2')
def __init__(self,driver):
self.driver = driver
def check_privacy_policy_checkout(self):
if not self.driver.find_element(*self._privacy_policy_checkout_loactor).is_selected():
self.click(self._privacy_policy_checkout_loactor)
def select_phone_number_login(self):
self.check_privacy_policy_checkout()
self.click(self._phone_number_login_locator)
- phoneNumberLoginPage.py 如下:
#coding= utf-8
from pom.common.common import Common
from selenium.webdriver.common.by import By
import time
class PhoneNumberLoginPage(Common):
_input_phone_number_locator = (By.CSS_SELECTOR , 'input.j-phone.txt.u-txt')
_input_password_locator = (By.CSS_SELECTOR , 'input#pw.j-pwd.u-txt')
_login_button_locator = (By.CSS_SELECTOR, 'a.j-primary.u-btn2.u-btn2-2')
_locate_mark_locator = (By.CSS_SELECTOR, 'i.u-icn.u-icn-25')
_get_login_failed_reason_locator = (By.CSS_SELECTOR,'div.j-err.u-err span')
def __init__(self,driver):
self.driver= driver
def input_phone_number_account(self,phone_number):
self.input_text(self._input_phone_number_locator,phone_number)
def input_password(self,password):
self.input_text(self._input_password_locator,password)
def click_login_button(self):
self.click(self._login_button_locator)
return self.get_actual_login_status()
def get_login_failed_reason(self):#查看页面上登入失败的原因
#self.driver.implicitly_wait(5)
time.sleep(2)
#return self.driver.find_element(self._get_login_failed_reason_locator).text.encode('utf-8')
return self.element_text(self._get_login_failed_reason_locator)
def get_actual_login_status(self): #主要是看账户登入真实情况
if self.is_element_displayed(self._locate_mark_locator):
#if self.driver.find_element(*self._locate_mark_locator).is_displayed: #如果页面上显示出!
return self.get_login_failed_reason() #打印登入失败的原因
else:
return '登入成功' #否则登入成功
3.测试用例层
test_login.py
#coding:utf-8
import sys
sys.path.append('../../') #调用不同目录下的包中的方法,需要添加环境变量
import unittest
from ddt import ddt,data,unpack,file_data
from selenium import webdriver
from pom.data.load_data import GetTestData,TestResult
from pom.common.common import Common
from pom.page.homePage import HomePage
from pom.page.scanOrOtherPage import ScanOrOtherPage
from pom.page.loginModePage import LoginModePage
from pom.page.phoneNumberLoginPage import PhoneNumberLoginPage
get_test_data = GetTestData()
write_test_result = TestResult()
test_data_list = get_test_data.get_test_data
@ddt
class TestLogin(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(4)
self.driver.maximize_window()
self.home_page = HomePage(self.driver)
self.scan_or_other_login_page = ScanOrOtherPage(self.driver)
self.login_mode_page = LoginModePage(self.driver)
self.phone_number_login_page = PhoneNumberLoginPage(self.driver)
def tearDown(self):
self.driver.quit()
@data(*test_data_list)
@unpack
def test_login_wangyiyun(self,url,phone_number,password,expext_result):
try:
self.home_page.click_login(url)
self.scan_or_other_login_page.select_other_login_mode()
self.login_mode_page.select_phone_number_login()
self.phone_number_login_page.input_phone_number_account(phone_number)
self.phone_number_login_page.input_password(password)
actual_login_result = self.phone_number_login_page.click_login_button()
if expext_result.encode('utf-8') == actual_login_result.encode('utf-8'):
write_test_result.write_test_result('Pass')
else:
write_test_result.write_test_result('Fail')
except Exception as e:
print e
actual_login_result = 'Fail,something wrong'
write_test_result.write_test_result('Fail:{}'.format(actual_login_result))
write_test_result.write_actual_result(actual_login_result)
self.driver.quit()
if __name__ =='__main__':
unittest.main()
4.测试数据与报告
#coding=utf-8
import xlrd
import openpyxl
#负责读取数据
class GetTestData():
def __init__(self):
self.excel = xlrd.open_workbook('../test_report/test_report.xlsx')
self.sheet = self.excel.sheet_by_name('test_data')
self.rows = self.sheet.nrows
self.cols = self.sheet.ncols
@property
def get_test_data(self):
data_list = []
data = []
for row in range(1,self.rows):
for i in self.sheet.row_values(row,1,5):
if type(i) == float: #表格中输入的手机号码是float类型,需要转换成int,不然会报错
data.append(int(i)) #用data列表存放转换后的每组测试数据
else:
data.append(i)
data_list.append(data)
data =[] #移除测试数据
return data_list
def test_result(self):
for row in range(1,self.rows):
self.sheet.cell_value(row,7)
# testr= GetTestData()
# print testr.get_test_data
class TestResult():
def __init__(self):
self.excel = openpyxl.load_workbook('../test_report/test_report.xlsx')
self.sheet = self.excel['test_data']
self.num = 2
self.result = 2
def write_actual_result(self,actual_result):
self.sheet.cell(row=self.num,column=6,value=actual_result)
self.num +=1
self.close_excel()
def write_test_result(self,test_result):
self.sheet.cell(row=self.result,column=7,value=test_result)
self.result +=1
self.close_excel()
def close_excel(self):
self.excel.save('../test_report/test_report.xlsx')
运行完test_login.py 文件去test_report.xlsx 文件中查看相应的测试结果:
test_report.xlsx
当执行发生异常时,故需要添加logging,去看具体异常原因,定位异常的地方。