selenium-python-unittest自動化測試框架(資料和程式碼完全分離)
阿新 • • 發佈:2019-02-02
這套框架適合使用的場景:
1、測試資料不多
2、執行人員不需要會程式碼
3、看報告的時候要看執行詳細結果
工程分為以下幾部分:
1、公用方法包-Util
2、需要呼叫的固定變數包-ProjectVar
3、元素路徑目錄-Conf
4、頁面元素常用動作方法+模組動作方法包-Action
5、測試用例執行包-TestUnittest
6、截圖目錄
看一下目錄組成結構:
- 1.公用方法包-Util
- 1.1 DirAndFile.py
- 這個模組是為了建立目錄用的
#encoding=utf-8
import os
from ProjectVar.Var import *
def createDir(path,dirName):
#os.path.join(x,y)是拼接路徑用的
dirPath=os.path.join(path,dirName)
#判斷路徑是否存在,存在則pass,否則新建
if os.path.exists(dirPath):
return dirPath
pass
else:
os.mkdir(dirPath)
return dirPath
- 1.2Excel.py
- 這個模組封裝了excel的常用操作方法
#encoding=utf-8
from openpyxl import Workbook
from openpyxl import load_workbook
from ProjectVar.Var import *
from openpyxl.styles import Border,Side,Font
class Excel(object):
def __init__(self):
self.font=Font(color=None)
self.colorDict={'red':'FFFF3030','green':'FF008B00'}
self.wb=load_workbook(test_path)
self.ws=self.wb.active
def rename(self,new_name):
#給表格重新命名
self.ws.title=new_name
self.wb.save(test_path)
def GetSheetName(self):
#獲取所有表格名稱
return self.wb.get_sheet_names()
def GetSheetByName(self,sheet_name):
#通過表格名稱獲取表格
self.ws=self.wb.get_sheet_by_name(sheet_name)
return self.ws
def GetCurrentSheetName(self):
#獲取當前表格名稱
return self.ws.title
def GetCellContent(self,row_num,col_num):
#獲取單元格內容
return self.ws.cell(row=row_num,column=col_num).value
def WriteCellContent(self,row_num,col_num,content):
#往指定的單元格里面寫入內容
self.ws.cell(row=row_num,column=col_num).value=content
self.wb.save(test_path)
def GetMaxRow(self):
#獲取最大行號
return self.ws.max_row
def GetMaxColumn(self):
#獲取最大列號
return self.ws.max_column
其實本次框架中沒有用到excel,但是我還是把他寫上,方便大家使用;【對於資料的傳遞也可以使用excel來操作的】
- 1.3GetConf.py
- 這個模組是為了操作配置檔案用的方法
#encoding=utf-8
import ConfigParser
from ProjectVar.Var import *
class ParsePageObjectRepositoryConfig(object):
def __init__(self):
self.cf=ConfigParser.ConfigParser()
self.cf.read(page_object_repository_path)
def getItemsFromSection(self,sectionName):
items=self.cf.items(sectionName)
return dict(items)
if __name__=='__main__':
#除錯程式碼
p=ParsePageObjectRepositoryConfig()
print p.getItemsFromSection('126mail_login')
print p.getItemsFromSection('126mail_login')['loginpage.frame'].split('//')[1]
print type(p.getItemsFromSection('126mail_login')['loginpage.frame'].split('//')[1])
- 1.4log.py
- 列印日誌用的(這裡可以不用這個,因為HTML就可以用)
#encoding=utf-8
import logging
import logging.config
from ProjectVar.Var import *
import os
#讀取日誌的配置檔案
logging.config.fileConfig(project_path+'\\Conf\\Logger.conf')
#選擇一個日誌格式
logger=logging.getLogger('example02')
def warning(message):
#列印warning級別的資訊(日誌級別較弱,最弱的是debug)
logger.warn(message)
def debug(message):
#列印debug級別的資訊(日誌資訊級別最弱
logger.debug(message)
def info(message):
#列印info級別資訊
logger.info(message)
def error(message):
#列印wornging級別資訊
logger.error(message)
if __name__=='__main__':
a = project_path + '\\Conf\\Logger.conf'
print os.path.exists(a)
print a
logging.config.fileConfig(project_path + '\\Conf\\Logger.conf')
info('info level')
warning('warning level')
error('error level')
debug('debug level')
- 1.5ObjectMap.py
- 這個模組是獲取頁面元素的方法,直接返回要操作的元素,後面呼叫的時候只需要傳遞定位元素方法和路徑就可以。
#encoding=utf-8
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.ui import Select
import time
def getElement(driver,locateType,locateExpression):
#獲取頁面單個元素
try:
wait=WebDriverWait(driver,10)
return wait.until(lambda x:x.find_element(locateType,locateExpression))
except Exception,e:
raise e
def getElements(driver,locateType,locateExpression):
#獲取頁面多個元素
try:
wait=WebDriverWait(driver,10)
return wait.until(lambda x:x.find_elements(locateType,locateExpression))
except Exception,e:
raise e
def getSelectElementWithIndex(driver,index_num):
#獲取select下拉框元素---index
select_element=Select(driver.find_element_by_xpath('//select'))
#列印已選中的文字
print select_element.all_selected_options[0].text
return select_element.select_by_index(index_num)
def getSelectElementWithText(driver,text):
#獲取select下拉框元素----text
select_element=Select(driver.find_element_by_xpath('//select'))
#列印已選中的文字
print select_element.all_selected_options[0].text
return select_element.select_by_visible_text(text)
def getSelectElementWithValue(driver,value):
#獲取select下拉框元素---value
select_element=Select(driver.find_element_by_xpath('select'))
#列印已選中的文字
print select_element.all_selected_options[0].text
return select_element.select_by_value(value)
- 2 .需要呼叫的公共變數包-ProjectVar
- 2.1Var.py
- 這個模組裡面是程式碼中用到的公用已知變數
#encoding=utf-8
import os
import time
#當前檔案路徑
file_path=__file__
#工程路徑
#os.path.dirname(__file__)當前檔案所在路徑
project_path=os.path.dirname(os.path.dirname(__file__)).decode('utf-8')
page_object_repository_path=project_path+'//Conf//PageObjectRepository .ini'
url='http:\\www.126.com'
chrom="c:\\Python27\\chromedriver"
ie="c:\\Python27\\IEDriverServer"
firefox="c:\\Python27\\geckodriver"
- 3 . 元素路徑目錄-Conf
- 3.1PageObjectRepository .ini
- 裡面都是頁面元素路徑的配置檔案
[configparse操作配置檔案的時候有坑]
[ini中的內容要全部小寫,否則讀取出來的時候會自動轉換成小寫,這樣就會發生匹配不上的情況]
[126mail_login]
loginpage.frame=xpath>//iframe[@id='x-URS-iframe']
loginpage.username=xpath>//span[.='@126.com']//preceding-sibling::input
loginpage.password=xpath>//label[.='密碼']//following-sibling::input[2]
loginpage.loginbutton=xpath>//a[@id='dologin']
[126mail_homepage]
home_age.addressbook=xpath>//div[text()='通訊錄']
[126mail_addcontactspage]
addcontacts_page.create_contacts_btn=xpath>//header/div[@role='toolbar']/div[@class='nui-toolbar-item'][1]
addcontacts_page.contact_person_name=xpath>//a[@title='編輯詳細姓名']/preceding-sibling::div/input
addcontacts_page.contact_person_email=xpath>//*[@id='iaddress_MAIL_wrap']//input
addcontacts_page.star_contacts=xpath>//span[text()='設為星標聯絡人']/preceding-sibling::span/b
addcontacts_page.contact_person_mobile=xpath>//*[@id='iaddress_TEL_wrap']//dd//input
addcontacts_page.contact_person_comment=xpath>//textarea
addcontacts_page.save_contace_person=xpath>//span[.='確 定']
- 4 .頁面元素常用動作方法+模組動作方法包-Action
- 4.1basic_function.py
- 這個模組裡面寫的是頁面操作的常用方法
#encoding=utf-8
from selenium import webdriver
from Util.ObjectMap import *
from ProjectVar.Var import *
from Util.DirAndFile import *
import traceback
import os
def open_browser(browserName,*arg):
#開啟瀏覽器
try:
if browserName.lower()=='ie':
driver=webdriver.Ie(executable_path=ie)
return driver
elif browserName.lower()=='chrome':
driver=webdriver.Chrome(executable_path=chrom)
return driver
elif browserName.lower()=='firefox':
driver=webdriver.Firefox(executable_path=firefox)
return driver
else:
print u"has no such browser"
pass
except Exception,e:
raise e
def visit_url(driver,url,*arg):
#訪問網頁
try:
driver.get(url)
except Exception,e:
raise e
def close_browser(driver):
#退出瀏覽器
try:
driver.quit()
except Exception,e:
raise e
def enter_frame(driver,locatorType,locatorExpression,*arg):
#切換frame
try:
driver.switch_to.frame(getElement(driver,locatorType,locatorExpression))
except Exception,e:
raise e
def get_out_frame(driver):
#切出來 frame
try:
driver.switch_to_default_content()
except Exception,e:
raise e
def input_string(driver,locatorType,locatorExpression,content,*arg):
#send_keys and clear
try:
getElement(driver, locatorType, locatorExpression).clear()
pause(0.5)
getElement(driver,locatorType,locatorExpression).send_keys(content)
pause(0.5)
except Exception,e:
raise e
def click_button(driver,locatorType,locatorExpression):
#點選操作
try:
getElement(driver, locatorType, locatorExpression).click()
except Exception,e:
raise e
def assert_keyword(driver,excepted_word,*arg):
#斷言
try:
assert True==(excepted_word in driver.page_source)
except AssertionError,e:
raise e
except Exception,e:
raise e
else:
print 'keyword : %s in page_source'%excepted_word
def pause(seconds,*arg):
time.sleep(float(seconds))
def max_window(driver):
#最大化視窗
try:
driver.maximize_window()
except Exception,e:
raise e
def get_element_out_to_can_see(driver,locatorType, locatorExpression,*arg):
#把元素拉倒可見的位置
try:
target = getElement(driver,locatorType, locatorExpression)
driver.execute_script("arguments[0].scrollIntoView();", target)
except Exception,e:
raise e
def scroll_page_to_buttom(driver):
#滾動條到最下方
try:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
except Exception,e:
raise e
def scroll_page_to_top(driver):
#滾動條到最上方
try:
driver.execute_script("window.scrollTo(0, 0);")
except Exception,e:
raise e
def capture_screen(driver,pictureName):
# 獲取正常截圖
dirPath=createDir(project_path+"//ScreenPictures//CapturePicture",time.strftime("%Y-%m-%d"))
os.chdir(dirPath)
try:
driver.get_screenshot_as_file(pictureName)
except Exception,e:
raise e
def error_screen(driver,pictureName):
# 獲取異常截圖
dirPath=createDir(project_path + "//ScreenPictures//ErrorPicture", time.strftime("%Y-%m-%d"))
os.chdir(dirPath)
try:
driver.get_screenshot_as_file(pictureName)
except Exception,e:
raise e
- 4.2 action_login.py
- 這個模組中寫的是login的操作步驟方法
#encoding=utf-8
from Action.basic_function import *
def login(driver,usernameAndpassword,*arg):
username,password=usernameAndpassword.split('||')
visit_url(driver,url)
pause(2)
enter_frame(driver,"id", "x-URS-iframe")
pause(1)
input_string(driver,"xpath", "//span[.='@126.com']//preceding-sibling::input", username)
pause(1)
input_string(driver,"xpath", "//label[.='密碼']//following-sibling::input[2]", password)
pause(1)
click_button(driver,"xpath", "//a[@id='dologin']")
- 4.3 action_addaddress.py
- 這個模組裡面封裝的是新增聯絡人的動作步驟
#encoding=utf-8
from Action.basic_function import *
driver=None
def add_address(driver,name,email,tel,comment,*arg):
click_button(driver,"xpath","//div[text()='通訊錄']")
pause(2)
click_button(driver,"xpath","//header/div[@role='toolbar']/div[@class='nui-toolbar-item'][1]")
pause(2)
input_string(driver,"xpath","//a[@title='編輯詳細姓名']/preceding-sibling::div/input",name)
pause(0.5)
input_string(driver,"xpath","//*[@id='iaddress_MAIL_wrap']//input",email)
pause(0.5)
input_string(driver,"xpath","//*[@id='iaddress_TEL_wrap']//dd//input",tel)
pause(0.5)
input_string(driver,"xpath","//textarea",comment)
pause(0.5)
click_button(driver,"xpath","//span[.='確 定']")
- 4.4 test_data.py
- 這個模組裡面寫的是用到的測試資料(所有用到的測試資料全在裡面,和程式碼是完全分離的)
#encoding=utf-8
#login的測試資料
login_info=("lxxxx_xxxx||ainixxxxxxxxx","lxxxx_xxxx||ainixxxxxxx")
#login後的斷言內容
login_keyword=u'退出'
#新增聯絡人測試資料
addressbook_info=[('ajin','[email protected]','18681867102','I am a beautiful girl ,I love my dad and mum!'),
('gangbeng','[email protected]','18689856963','I like meat !')]
#瀏覽器的選擇
browser_name='Chrome'
- 5 .測試用例執行包-TestUnittest
- 5.1 login_unittest.py
#encoding=utf-8
from HTMLTestRunner import HTMLTestRunner
import unittest
from Action.action_login import *
from Action.test_data import *
class TestLogin(unittest.TestCase):
def setUp(self):
self.driver=open_browser(browser_name)
def test_login(self):
for i in range(len(login_info)):
try:
login(self.driver,login_info[i])
pause(3)
self.assertIn(login_keyword,self.driver.page_source,login_keyword+' not in page_source')
except Exception,e:
print 'login error, ' + login_keyword + 'in page_source can not be found !'
error_screen(self.driver,'login-'+login_keyword+time.strftime('%H%M%S')+'.png')
print traceback.format_exc()
else:
capture_screen(self.driver,'login-'+login_keyword+time.strftime('%H%M%S')+'.png')
print 'login success, '+login_keyword+'in page_source can be found !'
finally:
print u'login 第%d次用例執行結束'%(i+1)
pause(2)
def tearDown(self):
self.driver.quit()
if __name__=='__main__':
suite=unittest.TestSuite()
suite.addTest(TestLogin('test_login'))
with open('HTMLForLogin.html','w')as fp:
runner=HTMLTestRunner(stream=fp,title='login report',description='report',verbosity=2)
runner.run(suite)
- 5.2 addaddress_unittest.py
- 增加聯絡人測試執行模組
#encoding=utf-8
from HTMLTestRunner import HTMLTestRunner
import unittest
from Action.action_addaddress import *
from Action.action_login import *
from Action.test_data import *
from Action.test_data import *
class TestAddAdress(unittest.TestCase):
def setUp(self):
self.driver=open_browser(browser_name)
def test_addAddress(self):
try:
login(self.driver, login_info[0])
pause(2)
except Exception,e:
raise e
else:
print 'login success'
finally:
print 'next is addaddressbook'
for i in range(len(addressbook_info)):
try:
add_address(self.driver,addressbook_info[i][0],addressbook_info[i][1],addressbook_info[i][2],addressbook_info[i][3])
pause(2)
self.assertIn(addressbook_info[i][0],self.driver.page_source,addressbook_info[i][0]+'not in page_source')
except Exception,e:
print 'addaddress error, ' + addressbook_info[i][0] + 'in page_source can not be found !'
error_screen(self.driver,'addressbook-'+addressbook_info[i][0]+time.strftime('%H%M%S')+'.png')
print traceback.format_exc()
else:
capture_screen(self.driver,'addressbook-'+addressbook_info[i][0]+time.strftime('%H%M%S')+'.png')
print 'addaddress success, '+addressbook_info[i][0]+'in page_source can be found !'
finally:
print u'addaddress 第%d次用例執行結束'%(i+1)
pause(2)
continue
def tearDown(self):
self.driver.quit()
if __name__=='__main__':
suite=unittest.TestSuite()
suite.addTest(TestAddAdress('test_addAddress'))
with open('HTMLForAddAddress.html','w')as fp:
runner=HTMLTestRunner(stream=fp,title='addAddress report',description='report',verbosity=2)
runner.run(suite)
我這裡沒有再開一個模組,來專門的用unittest去整合他們,大家可以自己操作一下,很簡單的!!
之前的1、2、3、4都是為了5的執行,將5中的兩個測試指令碼跑完之後,得到測試截圖和測試報告:
以上的例子是用126郵箱登入建立聯絡人做的測試框架,同樣的,在我們的專案中我也用了,還挺好用的,畢竟測試資料不多,這樣寫夠了,但是覺得還是要改進下,後面改進了,會繼續更新!!!