載地址HTMLTestRunner.py文件:
http://tungwaiyip.info/software/HTMLTestRunner.html
下載的適合python2,如果python3要修改一些內容
首先吧HTMLTestRunner文件添加到環境變量里,可以直接放到python的Lib目錄下
HTMLTestRunner是python標準庫unittest單元測試框架的一個擴展,用于生成HTML測試報告
#coding:utf-8
import unittest, HTMLTestRunner
class Testcase(unittest.TestCase): # 測試用例類
# 具體的測試用例,一定要以test開頭
def test1(self):
self.assertEqual(1, 1)
def test2(self):
self.assertEqual(2, 2)
if __name__=="__main__":
# 構造測試集
suite=unittest.TestSuite()
suite.addTest(unittest.makeSuite(Testcase)) # 執行該測試類所有用例
# 定義報告的存放路徑,以二進制寫的形式打開文件
f=open('test.html', 'wb')
# 定義測試報告,stream:報告存放路徑,title:報告標題,description:描述
runner=HTMLTestRunner.HTMLTestRunner(stream=f, title=u'測試用例標題', description=u'描述')
runner.run(suite) # 運行測試用例
f.close() # 關閉文件
返回結果(測試報告詳情):
--stream :存放報告寫入文件的存入區域
--title :測試報告的主題
--description :測試報告的描述
為了生成帶有中文描述的測試用例類和測試用例
在用例類和用例方法下,通過’’’ ‘’’或””” “””來添加備注
#coding:utf-8
import unittest, HTMLTestRunner
class Testcase(unittest.TestCase): # 測試用例類
u'''類名后加備注'''
def test1(self):
u'''用例后面加備注1'''
self.assertEqual(1, 1)
def test2(self):
u'''用例后面加備注2'''
self.assertEqual(2, 2)
if __name__=="__main__":
# 構造測試集
suite=unittest.TestSuite()
suite.addTest(unittest.makeSuite(Testcase))
# 定義報告的存放路徑,以二進制寫的形式打開文件
f=open('test.html', 'wb')
# 定義測試報告,stream:報告存放路徑,title:報告標題,description:描述
runner=HTMLTestRunner.HTMLTestRunner(stream=f, title=u'測試用例標題', description=u'描述')
runner.run(suite) # 運行測試用例
f.close() # 關閉文件
返回結果:
#coding:utf-8
import unittest, HTMLTestRunner, time
from unittest.loader import makeSuite
class Testcase(unittest.TestCase): # 測試用例類
# 具體的測試用例,一定要以test開頭
def test1(self):
self.assertEqual(1, 1)
def test2(self):
self.assertEqual(2, 2)
if __name__=="__main__":
# 構造測試集
suite=unittest.TestSuite()
suite.addTest(makeSuite(Testcase)) # 執行該測試類所有用例
# 定義報告的存放路徑,以二進制寫的形式打開文件
now=time.strftime("%y-%m-%d %H_%M_%S")
f=open('./' + now + 'test.html', 'wb')
# 定義測試報告,stream:報告存放路徑,title:報告標題,description:描述
runner=HTMLTestRunner.HTMLTestRunner(stream=f, title=u'測試用例標題', description=u'描述')
runner.run(suite) # 運行測試用例
f.close() # 關閉文件
返回結果:
將紅框里的內容注釋掉改成uo=o.decode('utf-8')
HTML 是用來描述網頁的一種語言。HTML 是一種在 Web 上使用的通用標記語言。HTML 允許你格式化文本,添加圖片,創建鏈接、輸入表單、框架和表格等等,并可將之存為文本文件,瀏覽器即可讀取和顯示。
新建一個test.html文件,內容如下
<!DOCTYPE html><html><head><meta charset="utf-8"><title>ZONGXP</title></head><body> <h1>我的第一個標題</h1><p>我的第一個段落。</p> </body></html>
其中:
保存后運行,即可在瀏覽器中打開如下界面
3.1 標題
HTML 標題(Heading)是通過<h1> - <h6> 標簽來定義的.
<!DOCTYPE html><html><head><meta charset="utf-8"><title>ZONGXP</title></head><body> <h1>這是標題 1</h1><h2>這是標題 2</h2><h3>這是標題 3</h3><h4>這是標題 4</h4><h5>這是標題 5</h5><h6>這是標題 6</h6> </body></html>
3.2 段落
HTML 段落是通過標簽 <p> 來定義的
<!DOCTYPE html><html><head><meta charset="utf-8"><title>ZONGXP</title></head><body> <p>這是一個段落。</p><p>這是一個段落。</p><p>這是一個段落。</p> </body></html>
3.3 鏈接
HTML 鏈接是通過標簽 <a> 來定義的
<!DOCTYPE html><html><head><meta charset="utf-8"><title>ZONGXP</title></head><body> <a href="https://blog.csdn.net/zong596568821xp">這是一個鏈接使用了 href 屬性</a> </body></html>
3.4 圖像
HTML 圖像是通過標簽 <img> 來定義的。注意: 圖像的名稱和尺寸是以屬性的形式提供的。
<!DOCTYPE html><html><head><meta charset="utf-8"><title>ZONGXP</title></head><body> <img src="zongxp.jpg" width="640" height="640" /> </body></html>
3.5 表格
表格由 <table> 標簽來定義。每個表格均有若干行(由 <tr> 標簽定義),每行被分割為若干單元格(由 <td> 標簽定義)。字母 td 指表格數據(table data),即數據單元格的內容。數據單元格可以包含文本、圖片、列表、段落、表單、水平線、表格等等。表格的表頭使用 <th> 標簽進行定義。如果不定義邊框屬性,表格將不顯示邊框。有時這很有用,但是大多數時候,我們希望顯示邊框。使用邊框屬性來顯示一個帶有邊框的表格:
<table border="1"> <tr> <th>Header 1</th> <th>Header 2</th> </tr> <tr> <td>row 1, cell 1</td> <td>row 1, cell 2</td> </tr> <tr> <td>row 2, cell 1</td> <td>row 2, cell 2</td> </tr></table>
4.1 基本文檔
<!DOCTYPE html><html><head><title>文檔標題</title></head><body>可見文本...</body></html>
4.2 基本標簽
<h1>最大的標題</h1><h2> . . . </h2><h3> . . . </h3><h4> . . . </h4><h5> . . . </h5><h6>最小的標題</h6> <p>這是一個段落。</p><br> (換行)<hr> (水平線)<!-- 這是注釋 -->
4.3 文本格式化
<b>粗體文本</b><code>計算機代碼</code><em>強調文本</em><i>斜體文本</i><kbd>鍵盤輸入</kbd> <pre>預格式化文本</pre><small>更小的文本</small><strong>重要的文本</strong> <abbr> (縮寫)<address> (聯系信息)<bdo> (文字方向)<blockquote> (從另一個源引用的部分)<cite> (工作的名稱)<del> (刪除的文本)<ins> (插入的文本)<sub> (下標文本)<sup> (上標文本)
4.4 鏈接
普通的鏈接:<a href="http://www.example.com/">鏈接文本</a>圖像鏈接: <a href="http://www.example.com/"><img src="URL" alt="替換文本"></a>郵件鏈接: <a href="mailto:webmaster@example.com">發送e-mail</a>書簽:<a id="tips">提示部分</a><a href="#tips">跳到提示部分</a>
4.5 圖片
<img src="URL" alt="替換文本" height="42" width="42">
4.6 樣式/區塊
<style type="text/css">h1 {color:red;}p {color:blue;}</style><div>文檔中的塊級元素</div><span>文檔中的內聯元素</span>
4.7 無序列表
<ul> <li>項目</li> <li>項目</li></ul>
4.8 有序列表
本次介紹的UI Test Framework 分為以下幾層,UI自動化測試框架主要思想Page Object 的思想,即:將一個頁面的元素封裝成一個類,本文以禪道項目為例:詳情如下:
分層介紹如下:
actions:動作層,封裝每個頁面的業務。
common:底層,封裝一些工具包,以及對Selenium 3 里面的元素定位,鼠標,鍵盤等動作進行二次封裝。
config:配置文件層,存放配置文件,一些主機地址信息,郵件地址,日志地址,驅動地址,日志級別設置,截圖地址,一些賬號信息等。
element_info:元素信息層,將每個頁面的元素封裝成類,類似的屬性是元素,方法是元素的動作。
element_info_datas:元素信息表層,每個頁面的元素信息都單獨存放在對應的excel表格中
logs :日志層
reports:報告層
runner:運行層
sample:測試層,用于代碼測試
screen_shot:存放截圖圖片層
test_data:測試數據層
testcases:測試用例集層
webdriver:存放瀏覽器驅動層
詳細說明如下:
common層:
base_page.py對selenium 3框架基本引用進行二次放在都放在這個文件里面
# desc:頁面基礎類
import os, time
from common.log_utils import logs_obj
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from common.config_utils import config_obj
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from common import HTMLTestReportCN
class BasePage(object):
def __init__(self, driver):
# self.driver=webdriver.Chrome()
self.driver=driver
def open_url(self, url):
self.driver.get(url)
logs_obj.info('打開url地址:{}'.format(url))
def set_browser_max(self):
self.driver.maximize_window()
logs_obj.info('窗口最大化')
def set_browser_min(self):
self.driver.minimize_window()
logs_obj.info('窗口最小化')
def refresh(self):
self.driver.refresh()
logs_obj.info('刷新')
def close_tab(self):
self.wait(2)
self.driver.close()
logs_obj.info('------- 關閉當前tab頁面 --------')
def quit_driver(self):
self.wait(1)
self.driver.quit()
logs_obj.info('------- 退出瀏覽器 --------')
def get_url(self):
value=self.driver.current_url
logs_obj.info('------- 獲取網頁url:{} --------'.format(value))
return value
def get_title(self):
value=self.driver.title
logs_obj.info('獲取網頁title:{}'.format(value))
return value
# 清空文本框的內容
def clear(self, element_info):
self.find_element(element_info).clear()
# self.username_inputbox={'element_name': '用戶名輸入框',
# 'locator_type': 'ID',
# 'locator_value': 'account',
# 'timeout': '5'}
def find_element(self, element_info):
'''
通過 element_info (元素識別的數據,返回一個元素)
:param element_info:元素識別信息字典
:return: element
id,name,class,tag,linktext,plinktext,xpath,css
'''
try:
locator_type_name=element_info['locator_type']
locator_value_info=element_info['locator_value']
locator_timeout=element_info['timeout']
if locator_type_name=='id':
locator_type=By.ID
elif locator_type_name=='xpath':
locator_type=By.XPATH
elif locator_type_name=='name':
locator_type=By.NAME
elif locator_type_name=='class':
locator_type=By.CLASS_NAME
elif locator_type_name=='css':
locator_type=By.CSS_SELECTOR
elif locator_type_name=='tag':
locator_type=By.TAG_NAME
elif locator_type_name=='linktext':
locator_type=By.LINK_TEXT
elif locator_type_name=='plinktext':
locator_type=By.PARTIAL_LINK_TEXT
# self.driver.find_element(By.XPATH,'//li[@data-id="product"]')
# 顯示等待識別元素
element=WebDriverWait(self.driver, locator_timeout).until(
lambda x: x.find_element(locator_type, locator_value_info)) # 最核心的代碼
logs_obj.info('[{}] 識別成功'.format(element_info['element_name']))
except Exception as e:
logs_obj.info('[{}] 識別不成功,原因是:{}'.format(element_info['element_name'], e.__str__()))
self.screenshot_as_file()
return element
# 封裝元素操作方法
def click(self, element_info):
element=self.find_element(element_info)
element.click()
logs_obj.info('點擊:{}'.format(element_info['element_name']))
# 元素輸入操作
def send_keys(self, element_info, content):
element=self.find_element(element_info)
element.send_keys(content)
logs_obj.info('[{}]中輸入{}'.format(element_info['element_name'], content))
# 獲取元素的某個屬性值
def get_attribute(self, element_info):
title=self.find_element(element_info).get_attribute('title')
logs_obj.info('title是:{}'.format(title))
return title
# 獲取元素的某個屬性值
def get_text_value(self, element_info):
text=self.find_element(element_info).text
logs_obj.info('text是:{}'.format(text))
return text
# 切框架:思路1 通過元素是被數據字典,獲取元素再切
def switch_to_frame_by_element(self, element_info):
element=self.driver.find_element(element_info)
self.driver.switch_to.frame(element)
logs_obj.info('通過元素切換框架,該元素為:{}'.format(element_info['locator_value']))
# 切框架:思路2 使用id或name切
def switch_to_frame_id_or_name(self, id_or_name):
self.driver.switch_to.frame(id_or_name)
logs_obj.info('通過id或name切換框架,id或name為:{}'.format(id_or_name))
# 切框架:思路3 把前面兩種思路整合,封裝成一個統一的方法
def switch_to_frame(self, **element_dict):
if 'id' in element_dict.keys():
self.driver.switch_to.frame(element_dict['id'])
logs_obj.info('通過id切換框架,id為:{}'.format(element_dict['id']))
elif 'name' in element_dict.keys():
self.driver.switch_to.frame(element_dict['name'])
logs_obj.info('通過name切換框架,name為:{}'.format(element_dict['name']))
elif 'element_info' in element_dict.keys():
element=self.find_element(element_dict['element_info'])
logs_obj.info('通過element_info切換框架,element_info為:{}'.format(element_dict['element_info']))
self.driver.switch_to.frame(element)
return element_dict
def switch_to_default_content(self):
self.driver.switch_to.default_content()
# 彈出框封裝
# def switch_to_alert(self,action='accept',time_out=config_obj.time_out):
# self.wait(time_out)
# alert=self.driver.switch_to.alert
# alert_text=alert.text
# if action=='accept':
# alert.accept() #確認
# else:
# alert.dismiss
# return alert_text
def switch_to_alert_2(self, action='accept', time_out=config_obj.time_out):
WebDriverWait(self.driver, time_out).until(EC.alert_is_present())
alert=self.driver.switch_to.alert
logs_obj.info('----------- 切換到彈框 -----------')
alert_text=alert.text
logs_obj.info('-------- 彈框的文本內容為:{} -------'.format(alert_text))
self.wait(3)
if action=='accept':
alert.accept()
logs_obj.info('-------- 點擊彈框的確定按鈕! ---------')
else:
alert.dismiss()
logs_obj.info('---------- 點擊彈框的取消按鈕 -----------')
return alert_text
# 切句柄
# 獲取當前頁面的句柄
def get_window_handle(self):
logs_obj.info('---- 獲取窗口的句柄:{} ---------'.format(self.driver.current_window_handle))
return self.driver.current_window_handle
# 切句柄
def switch_to_window_by_handle(self, window_handle):
self.driver.switch_to.window(window_handle)
logs_obj.info('-------- 進行切換句柄,句柄為:{} ----------'.format(window_handle))
# 通過title切
# def switch_to_window_by_title(self,title):
# window_handles=self.driver.window_handles
# for window_handle in window_handles:
# self.driver.switch_to.window(window_handle)
# if self.get_title()==title:
# break;
# 通過url切
# def switch_to_window_by_url(self,url):
# window_handles=self.driver.window_handles
# for window_handle in window_handles:
# self.driver.switch_to.window(window_handle)
# if self.get_url()==url:
# break;
# 切句柄繼續封裝 加等待時間,只檢查標題標題,url的部分內容
def switch_to_window_by_title(self, title):
window_handles=self.driver.window_handles
for window_handle in window_handles:
self.driver.switch_to.window(window_handle)
if WebDriverWait(self.driver, config_obj.time_out).until(EC.title_contains(title)):
logs_obj.info('--------- 通過title({})切換窗口:-----------'.format(title))
break;
def switch_to_window_by_url(self, url):
window_handles=self.driver.window_handles
for window_handle in window_handles:
self.driver.switch_to.window(window_handle)
if WebDriverWait(self.driver, config_obj.time_out).until(EC.title_contains(url)):
logs_obj.info('--------- 通過url({})切換窗口:-----------'.format(url))
break;
# 修改某個元素的屬性
def set_element_attribute(self, element_info, attribute_name, attribute_value):
js='arguments[0].setAttribute("%s","%s");' % (attribute_name, attribute_value)
el=self.find_element(element_info)
self.__execute_script(js, el)
logs_obj.info('[{}],正在執行修改[{}]屬性操作,修改成:{}'.format(element_info['element_name'], attribute_value))
# 移除某個屬性
def remove_element_attribute(self, element_info, attribute_name):
js='arguments[0].removeAttribute("%s");' % attribute_name
el=self.find_element(element_info)
self.__execute_script(js, el)
logs_obj.info('[{}],正在執行移除[{}]屬性操作'.format(element_info['element_name'], attribute_name))
# 滾動條
def scroll(self, height):
self.wait(2)
js='window.scrollBy(0,{});'.format(height) # height:正數向下滾,負數向上滾
self.__execute_script(js)
logs_obj.info('正在執行頁面滾動操作,滾動的高度為:{}'.format(height))
# 繼續封裝 selenium 執行 js 腳本 深入封裝
def __execute_script(self, js, element=None):
if element:
self.driver.execute_script(js, element)
logs_obj.info('[{}]:正在進行js操作,js代碼為'.format(element['element_name'], js))
else:
self.driver.execute_script(js)
logs_obj.info('正在執行js,js是{}'.format(js))
# 固定等待
def wait(self, s=config_obj.time_out):
time.sleep(s)
logs_obj.info('固定等待:%s' % s)
# 隱式等待
def implicitly_wait(self, seconds=config_obj.time_out):
self.driver.implicitly_wait(seconds)
logs_obj.info('------- 瀏覽器設置隱式等待:{} --------'.format(seconds))
# 顯示等待
# 鼠標懸停
def move_to_element_by_mouse(self, element_info):
element=self.find_element(element_info)
ActionChains(self.driver).move_to_element(element)
logs_obj.info('[{}]:元素進行懸停'.format(element_info['element_name']))
# 長按不停
def long_press_element(self, element_info):
element=self.find_element(element_info)
ActionChains(self.driver).click_and_hold(element).perform()
logs_obj.info('[{}]:元素進行長按'.format(element_info['element_name']))
# 鼠標右擊
def right_click_element(self, element_info):
element=self.find_element(element_info)
ActionChains(self.driver).context_click(element).perform()
logs_obj.info('[{}]:元素進行右擊'.format(element_info['element_name']))
# 截圖
# def screenshot_as_file(self, *screenshot_path):
# # 如果沒有喘截圖路徑,則將截圖放入默認路徑,
# if len(screenshot_path)==0:
# screenshot_filepath=config_obj.screen_shot_path
# else:
# screenshot_filepath=screenshot_path[0]
# now=time.strftime('%Y_%m_%d_%H_%M_%S')
# current_dir=os.path.dirname(__file__)
# screenshot_filepath=os.path.join(current_dir, '..', screenshot_filepath,
# 'UTest_%s.png' % now)
# self.driver.save_screenshot(screenshot_filepath)
# logs_obj.info(' 截圖保存成功,圖片位置:{}'.format(screenshot_filepath))
# 第二次講截圖
def screenshot_as_file(self):
'''
把錯誤截圖放到HTML中
:return:
'''
report_path=os.path.join(os.path.abspath(__file__),'..',config_obj.report_path)
report_dir=HTMLTestReportCN.ReportDirectory('report_path')
report_dir.get_screenshot(self.driver)
# 下拉定位,一下分別通過Select類的索引
def select_by_element_info(self, element_info):
element=self.find_element(element_info)
self.click(element)
def select_by(self, element_info, **by_index_or_value_or_visible_text):
element=self.find_element(element_info)
select=Select(element)
if 'index' in by_index_or_value_or_visible_text.keys():
select.select_by_index(by_index_or_value_or_visible_text['index'])
logs_obj.info('通過select的index定位到該元素,index值為:{}'.format(by_index_or_value_or_visible_text['text']))
elif 'value' in by_index_or_value_or_visible_text.keys():
select.select_by_value(by_index_or_value_or_visible_text['value'])
logs_obj.info('通過select的value定位到該元素,value值為:{}'.format(by_index_or_value_or_visible_text['value']))
elif 'text' in by_index_or_value_or_visible_text.keys():
select.select_by_visible_text(by_index_or_value_or_visible_text['text'])
logs_obj.info('通過select的text定位到該元素,text值為:{}'.format(by_index_or_value_or_visible_text['text']))
if __name__=='__main__':
from common.browser import Browser
driver=Browser().get_driver()
base_page=BasePage(driver)
base_page.open_url('https://www.baidu.com')
base_page.scroll(1000)
browser.py主要對Google、Firefox、msedge三大瀏覽器驅動進行封裝:
瀏覽器驅動需要下載本地計算機瀏覽器對應的版本:
瀏覽器驅動
# @desc:瀏覽器封裝
import os
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from common.config_utils import config_obj
from selenium.webdriver.chrome.options import Options
from common.log_utils import logs_obj
dri_path=os.path.join(os.path.dirname(__file__), '..', config_obj.get_driver_path)
class Browser():
def __init__(self, driver_path=dri_path):
self.__driver_path=driver_path
def __get_chrome_driver(self):
chrome_options=Options()
chrome_options.add_argument('--disable-gpu') # 谷歌文檔提到需要加上這個屬性來規避bug
chrome_options.add_argument('lang=zh_CN.UTF-8') # 設置默認編碼為utf-8
chrome_options.add_experimental_option('useAutomationExtension', False) # 取消chrome受自動控制提示
chrome_options.add_experimental_option("excludeSwitches", ['enable-automation']) # 取消chrome受自動控制提示
driver_path=os.path.join(self.__driver_path, 'chromedriver.exe')
driver_server=Service(driver_path)
chrome_driver=webdriver.Chrome(service=driver_server, options=chrome_options)
logs_obj.info('----- 初始化google瀏覽器,并啟動 -----')
return chrome_driver
def __get_firefox_driver(self):
firefox_driver_path=os.path.join(self.__driver_path, 'geckodriver.exe')
driver_server=Service(firefox_driver_path)
firefox_driver=webdriver.Firefox(service=driver_server)
logs_obj.info('----- 初始化firefox瀏覽器,并啟動 -----')
return firefox_driver
def __get_edge_driver(self):
edge_driver_path=os.path.join(self.__driver_path, 'msedgedriver.exe')
driver_server=Service(edge_driver_path)
edge_driver=webdriver.Edge(service=driver_server)
logs_obj.info('----- 初始化edge瀏覽器,并啟動 -----')
return edge_driver
def get_driver(self):
##設置默認驅動 chrome,firefox,msedge
if config_obj.get_driver_name=='chrome':
driver=self.__get_chrome_driver()
logs_obj.info('------- 配置文件配置的瀏覽器驅動是:{} --------'.format(config_obj.get_driver_name))
elif config_obj.get_driver_name=='firefox':
driver=self.__get_firefox_driver()
logs_obj.info('------- 配置文件配置的瀏覽器驅動是:{} --------'.format(config_obj.get_driver_name))
elif config_obj.get_driver_name=='msedge':
driver=self.__get_edge_driver()
logs_obj.info('------- 配置文件配置的瀏覽器驅動是:{} --------'.format(config_obj.get_driver_name))
return driver
config_utils.py讀取配置文件類:
config.ini文件內容為:
配置文件所在的目錄
[name]
name1=test
name2=dev01
name3=dev02
name4=test01
name5=test02
[password]
password1=xxxx
password2=xxxx
password3=xxxx
password4=xxxx
password5=xxxx
[ZenTao_url]
url=http://xx.xxx.xxxx.xx/zentao/www/index.php?m=user&f=login
[default]
driver_path=webdriver
#日志路徑
log_path=logs
#日志級別 0 NOTSET 10 DEBUG 20 INFO 30 WARNING 40 ERROR 50 CRITICAL
log_level=20
#設置默認驅動 chrome,firefox,msedge
driver_name=chrome
#元素識別信息路徑
element_info_path=element_info_datas
#默認等待時間
time_out=30
#默認存放截圖目錄
screen_shot_path=screen_shot
#默認登錄的賬戶名和密碼
username=test01
password=xxxxxxx
#測試數據路徑
test_data_path=test_data
#測試用例路徑
case_path=testcases
#測試報告路徑
report_path=reports/
[email]
#發送服務器
smtp_server=smtp.qq.com
#發送賬戶
smtp_sender=xxxxx@qq.com
#QQ第三方登錄密碼
smtp_password=xxxxx
#測接收人
smtp_receiver=xxxxx@qq.com
#抄送人
smtp_cc=2656343994@qq.com
#郵件標題
smtp_subject=禪道UI自動化測試報告
config_utils.py類:
# 讀取配置文件
import configparser, os
config_path=os.path.join(os.path.dirname(__file__), '../config/config.ini')
class ConfigUtils:
def __init__(self, cof_path):
self.config_path=cof_path
self.conf=configparser.ConfigParser()
self.conf.read(self.config_path, encoding='utf-8')
@property
def get_zentao_url(self):
return self.conf.get('ZenTao_url', 'url')
@property
def get_name_01(self):
return self.conf.get('name', 'name1')
@property
def get_name_02(self):
return self.conf.get('name', 'name2')
@property
def get_password_01(self):
return self.conf.get('password', 'password1')
@property
def get_password_02(self):
return self.conf.get('password', 'password2')
@property
def get_driver_path(self):
return self.conf.get('default', 'driver_path')
@property
def get_log_path(self):
return self.conf.get('default', 'log_path')
@property
def get_log_level(self):
return int(self.conf.get('default', 'log_level'))
# 獲取默認驅動名稱
@property
def get_driver_name(self):
return self.conf.get('default', 'driver_name')
# 獲取默認超時時間
@property
def time_out(self):
return float(self.conf.get('default', 'time_out'))
# 獲取截圖默認路徑
@property
def screen_shot_path(self):
return self.conf.get('default', 'screen_shot_path')
@property
def user_name(self):
return self.conf.get('default', 'username')
@property
def pass_word(self):
return self.conf.get('default', 'password')
@property
def test_data_path(self):
return self.conf.get('default', 'test_data_path')
# 測試用例路徑
@property
def case_path(self):
return self.conf.get('default', 'case_path')
# 測試報告路徑
@property
def report_path(self):
return self.conf.get('default', 'report_path')
# 獲取email的smtp_server
@property
def smtp_server(self):
return self.conf.get('email', 'smtp_server')
# 獲取email的smtp_sender
@property
def smtp_sender(self):
return self.conf.get('email', 'smtp_sender')
# 獲取email的smtp_password
@property
def smtp_password(self):
return self.conf.get('email', 'smtp_password')
# 獲取email的smtp_receiver
@property
def smtp_receiver(self):
return self.conf.get('email', 'smtp_receiver')
# 獲取email的smtp_cc
@property
def smtp_cc(self):
return self.conf.get('email', 'smtp_cc')
# 獲取email的smtp_subject
@property
def smtp_subject(self):
return self.conf.get('email', 'smtp_subject')
#element_info_path
@property
def element_info_path(self):
return self.conf.get('default', 'element_info_path')
config_obj=ConfigUtils(config_path)
element_data_utils.py讀取excel元素文件類,excel元素文件目錄結構如下,文件內容如圖:
一個頁面一個excel文件
登錄頁面元素信息如下圖,其它頁面元素類似:
element_data_utils.py類
# encoding: utf-8
# @author: newdream_daliu
# @file: element_data_utils.py
# @time: 2022-07-10 17:12
# @desc: 讀取頁面元素類
import os
import xlrd
from common.config_utils import config_obj
current_path=os.path.dirname(__file__)
excel_path=os.path.join(current_path, '..',config_obj.element_info_path)
#element_info_datas/login/login_page.xlsx
#固定元素的總路徑/模塊路徑/頁面名稱.xlsx
class ElementDataUtils():
def __init__(self,module_name,page_name, element_path=excel_path): # 將頁面名稱定義
self.element_path=element_path
self.element_path=os.path.join(self.element_path,module_name,page_name+'.xlsx')
self.workbook=xlrd.open_workbook(self.element_path)
self.sheet=self.workbook.sheet_by_index(0) # 每次取第一個sheet
self.row_count=self.sheet.nrows
def get_element_info(self):
element_infos={}
for i in range(1, self.row_count):
# if self.sheet.cell_value(i, 2)==page_name:
element_info={}
element_info['element_name']=self.sheet.cell_value(i, 1)
element_info['locator_type']=self.sheet.cell_value(i,2)
element_info['locator_value']=self.sheet.cell_value(i, 3)
timeout_value=self.sheet.cell_value(i,4)
#方法1:
# if timeout_value=='':
# timeout_value=config_obj.time_out #如果沒有設置,就取config.ini設置的默認值
# else:
# timeout_value=float(timeout_value) #如果元素表設置了默認值則就轉成浮點型
# element_info['timeout']=timeout_value
# 方法2:
timeout_value=float(timeout_value) if isinstance(timeout_value,float) else config_obj.time_out
element_info['timeout']=timeout_value
element_infos[self.sheet.cell_value(i, 0)]=element_info
return element_infos
if __name__=='__main__':
elements=ElementDataUtils('login','login_page').get_element_info()
print(elements)
# elements=ElementDataUtils('main').get_element_info('main_page')
# print(elements)
# elements=ElementDataUtils('login').get_element_info('login_page')
# print(elements)
email_util.py 發送郵件類
import smtplib, os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from common.log_utils import logs_obj
from email.mime.base import MIMEBase
from email import encoders
from common.config_utils import config_obj
from common import zip_utils
class EmailUtils:
def __init__(self, smtp_body, smtp_file_path=None):
self.smtp_server=config_obj.smtp_server
self.smtp_sender=config_obj.smtp_sender
self.smtp_password=config_obj.smtp_password
self.smtp_receiver=config_obj.smtp_receiver
self.smtp_cc=config_obj.smtp_cc
self.smtp_subject=config_obj.smtp_subject
self.smtp_body=smtp_body
self.smtp_file=smtp_file_path
def mail_content(self):
if self.smtp_file !=None:
if self.smtp_file.split('.')[-1].__eq__('zip'):
return self.__mail_zip_content()
# elif擴展
else:
return self.__mail_text_content()
def mail_content_by_zip(self):
report_zip_path=self.smtp_file + '/../禪道UI自動化測試報告.zip'
zip_utils.zip_dir(self.smtp_file, report_zip_path)
self.smtp_file=report_zip_path
message=self.mail_content()
return message
def __mail_text_content(self):
message=MIMEText(self.smtp_body, 'html', 'utf-8')
message['From']=self.smtp_sender
message['To']=self.smtp_receiver
message['Cc']=self.smtp_cc
message['Subject']=self.smtp_subject
return message
def __mail_zip_content(self):
message=MIMEMultipart()
with open(self.smtp_file, 'rb') as f:
mime=MIMEBase('zip', 'zip', filename=self.smtp_file.split('/')[-1])
mime.add_header('Content-Disposition', 'attachment',
filename=('gb2312', '', self.smtp_file.split('/')[-1]))
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id', '0')
mime.set_payload(f.read())
encoders.encode_base64(mime)
message.attach(mime)
message.attach(MIMEText(self.smtp_body, 'html', 'utf-8'))
message['From']=self.smtp_sender
message['To']=self.smtp_receiver
message['Cc']=self.smtp_cc
message['Subject']=self.smtp_subject
return message
def zip_send_mail(self):
try:
smtp=smtplib.SMTP()
smtp.connect(self.smtp_server, 25) # 25 為 SMTP 端口號
smtp.login(self.smtp_sender, self.smtp_password)
except:
smtp=smtplib.SMTP_SSL()
smtp.login(self.smtp_sender, self.smtp_password)
mail_content=self.mail_content_by_zip()
try:
smtp.sendmail(self.smtp_sender, self.smtp_receiver.split(',') + self.smtp_cc.split(','),
mail_content.as_string())
logs_obj.info('郵件發送人是:{},郵件接收人是;{},郵件抄送人是:{}'.format(self.smtp_sender,
self.smtp_receiver.split(',')
,self.smtp_cc.split(',')))
print("郵件發送成功")
except smtplib.SMTPException:
logs_obj.info('郵件發送失敗,失敗原因:{}'.format(smtplib.SMTPException))
smtp.close()
logs_obj.info('發送郵件結束')
excel_util.py讀取excel工具包:
# encoding:utf-8
# @author:yangshhiyu
# @file:excel_utils.py
# @time:2022/7/2415:29
# @desc:底層讀取excel底層封裝
import xlrd, os
from common.config_utils import config_obj
# current_path=os.path.dirname(__file__)
# el_path=os.path.join(current_path, '../element_info_datas/element_info_datas.xlsx')
# test_data_path=os.path.join(current_path,'..',config_obj.test_data_path)
class ExcelUtils():
def __init__(self, excel_path, sheet_name=None):
self.excel_path=excel_path
self.sheet_name=sheet_name
self.sheet_data=self.__get_sheet_data()
def __get_sheet_data(self):
'''
通過sheet_name 獲取一個sheet,如果沒有就返回第一個sheet
:return: sheet data
'''
workbook=xlrd.open_workbook(self.excel_path)
if self.sheet_name:
sheet=workbook.sheet_by_name(self.sheet_name)
else:
sheet=workbook.sheet_by_index(0)
return sheet
@property
def __get_row_count(self):
'''獲取總的行數'''
row_count=self.__get_sheet_data().nrows
return row_count
@property
def __get_col_count(self):
'''獲取總的列數 '''
rol_count=self.__get_sheet_data().ncols
return rol_count
def get_sheet_data_by_list(self):
'''
通過讀取excel中數據
:return: [[],[],[]....]
'''
all_excel_data=[] # 總的數據
for rownum in range(self.__get_row_count):
row_excel_data=[] # 一行的數據
for colnum in range(self.__get_col_count):
cell_value=self.__get_sheet_data().cell_value(rownum, colnum)
row_excel_data.append(cell_value)
all_excel_data.append(row_excel_data)
return all_excel_data
if __name__=='__main__':
current_path=os.path.dirname(__file__)
el_path=os.path.join(current_path, '../element_info_datas/element_info_datas.xlsx')
test_data_path=os.path.join(current_path, '..', config_obj.test_data_path)
datas=ExcelUtils(test_data_path,'login_suit').get_sheet_data_by_list()
for data in datas:
print(data)
HTMLTestReportCN.py生產測試報告類,可以自行網上下載:
log_util.py日志文件類:
日志文件目錄:
import logging, os,time
from common.config_utils import config_obj
logs_path=os.path.join(os.path.dirname(__file__), '..',config_obj.get_log_path)
class LogUtils(object):
def __init__(self, logger=None):
self.log_name=os.path.join(logs_path,'UITest_%s.log'%time.strftime('%Y_%m_%d'))
self.logger=logging.getLogger(logger)
self.logger.setLevel(config_obj.get_log_level) #日志級別,info 級別
self.fh=logging.FileHandler(self.log_name, encoding='utf-8')
self.fh.setLevel(config_obj.get_log_level)
self.ch=logging.StreamHandler() #寫控制帶
self.ch.setLevel(config_obj.get_log_level)
formatter=logging.Formatter("[%(asctime)s] - %(filename)s - [line:%(lineno)d] - %(levelname)s: %(message)s")
self.fh.setFormatter(formatter)
self.ch.setFormatter(formatter)
self.logger.addHandler(self.fh)
self.logger.addHandler(self.ch)
self.fh.close()
self.ch.close()
def info(self, message):
return self.logger.info(message)
def error(self, message):
return self.logger.error(message)
def debug(self, message):
return self.logger.debug(message)
def critical(self, message):
return self.logger.critical(message)
def warning(self, message):
return self.logger.warning(message)
logs_obj=LogUtils()
selenium_base_case.py 測試用例初始化,清理工作封裝:
# @desc:unittest 的二次封裝
import unittest
from common.config_utils import config_obj
from common.browser import Browser
from common.base_page import BasePage
from common.log_utils import logs_obj
class SeleniumBaseCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.url=config_obj.get_zentao_url
def setUp(self):
self.driver=Browser().get_driver()
self.base_page=BasePage(self.driver)
self.base_page.set_browser_max()
self.base_page.implicitly_wait()
self.base_page.open_url(self.url)
def tearDown(self):
errors=self._outcome.errors
for test,exc_info in errors:
if exc_info:
self.base_page.wait(3)
self.base_page.screenshot_as_file()
logs_obj.info('----------- 測試用例執行完畢 --------')
self.base_page.quit_driver()
test_data_utils.py讀取測試用例測試數據封裝:
# encoding:utf-8
# @author:yangshhiyu
# @file:test_data_utils.py
# @time:2022/7/2720:54
# @desc:讀取測試用例數據
import os
from common.excel_utils import ExcelUtils
from common.config_utils import config_obj
class TestDataUtils:
def __init__(self,test_suit_name,test_file_name,test_class_name):
current_path=os.path.dirname(__file__)
test_data_path=os.path.join(current_path, '..', config_obj.test_data_path)
test_data_path=os.path.join(test_data_path,test_suit_name,test_file_name+'.xlsx')
self.test_class_name=test_class_name
self.excel_data=ExcelUtils(test_data_path,test_class_name).get_sheet_data_by_list()
self.excel_row=len(self.excel_data)
def convert_exceldata_to_testdata(self):
'''把excel表中的數據轉換成用例的字典數據'''
test_data_infos={}
for i in range(1,self.excel_row):
test_data_info={}
# if self.excel_data[i][2].__eq__(self.test_class_name):
test_data_info['test_name']=self.excel_data[i][1]
test_data_info['isnot']=self.excel_data[i][2]
test_data_info['isnot']=False if self.excel_data[i][2].__eq__('是') else True
test_data_info['expected_result']=self.excel_data[i][3]
test_parameter={}
for j in range(4,len(self.excel_data[i])):
if self.excel_data[i][j].__contains__('=') and len(self.excel_data[i][j])>2:
parameter_info=self.excel_data[i][j].split('=')
test_parameter[parameter_info[0]]=parameter_info[1]
test_data_info['test_parameter']=test_parameter
test_data_infos[self.excel_data[i][0]]=test_data_info
return test_data_infos
if __name__=='__main__':
infos=TestDataUtils('qa_suit','qa_case', 'CreateBugSuit').convert_exceldata_to_testdata()
for info in infos.values():
print(info)
zip_utils.py 將測試報告壓縮成zip文件,進行封裝:
# encoding:utf-8
# @author:yangshhiyu
# @file:test_data_utils.py
# @time:2022/7/2720:54
# @desc:讀取測試用例數據
import os
from common.excel_utils import ExcelUtils
from common.config_utils import config_obj
class TestDataUtils:
def __init__(self,test_suit_name,test_file_name,test_class_name):
current_path=os.path.dirname(__file__)
test_data_path=os.path.join(current_path, '..', config_obj.test_data_path)
test_data_path=os.path.join(test_data_path,test_suit_name,test_file_name+'.xlsx')
self.test_class_name=test_class_name
self.excel_data=ExcelUtils(test_data_path,test_class_name).get_sheet_data_by_list()
self.excel_row=len(self.excel_data)
def convert_exceldata_to_testdata(self):
'''把excel表中的數據轉換成用例的字典數據'''
test_data_infos={}
for i in range(1,self.excel_row):
test_data_info={}
# if self.excel_data[i][2].__eq__(self.test_class_name):
test_data_info['test_name']=self.excel_data[i][1]
test_data_info['isnot']=self.excel_data[i][2]
test_data_info['isnot']=False if self.excel_data[i][2].__eq__('是') else True
test_data_info['expected_result']=self.excel_data[i][3]
test_parameter={}
for j in range(4,len(self.excel_data[i])):
if self.excel_data[i][j].__contains__('=') and len(self.excel_data[i][j])>2:
parameter_info=self.excel_data[i][j].split('=')
test_parameter[parameter_info[0]]=parameter_info[1]
test_data_info['test_parameter']=test_parameter
test_data_infos[self.excel_data[i][0]]=test_data_info
return test_data_infos
if __name__=='__main__':
infos=TestDataUtils('qa_suit','qa_case', 'CreateBugSuit').convert_exceldata_to_testdata()
for info in infos.values():
print(info)
元素信息層:
登錄頁面元素信息類,login_page.py:
# desc:登錄頁面
from common.base_page import BasePage
from common.browser import Browser
from common.element_data_utils import ElementDataUtils
from common.log_utils import logs_obj
elements=ElementDataUtils('login','login_page').get_element_info()
class LoginPage(BasePage):
def __init__(self,driver):
# 元素識別分離
super().__init__(driver) # 初始化父類構建函授
logs_obj.info('------- 啟動瀏覽器 -------')
self.username_input_box=elements['username_input_box']
self.password_input_box=elements['password_input_box']
self.login_button=elements['login_button']
self.keepLogin_checkbox=elements['keepLogin_checkbox']
def input_username(self, name):
self.send_keys(self.username_input_box, name)
def input_password(self, password):
self.send_keys(self.password_input_box, password)
def click_login(self):
self.click(self.login_button)
def click_keep_login(self):
self.click(self.keepLogin_checkbox)
#封裝一個登錄失敗,彈出的提示框中點確認,并返回提示框中的內容
def get_login_fail_alert_content(self):
return self.switch_to_alert_2()
if __name__=='__main__':
# 驅動處理
login_page=LoginPage(Browser().get_driver())
login_page.open_url('http://47.107.178.45/zentao/www/index.php?m=user&f=loginz')
login_page.set_browser_max()
login_page.input_username('test01')
login_page.input_password('newdream13')
login_page.click_login()
login_page.get_login_fail_alert_content()
login_page.quit_driver()
主頁面元素信息類,main_page.py
# desc主頁面類
from common.browser import Browser
from element_info.login.login_page import LoginPage
from common.element_data_utils import ElementDataUtils
from common.base_page import BasePage
from common.log_utils import logs_obj
class MainPage(BasePage):
def __init__(self, driver):
# 元素識別分離
super().__init__(driver) # 初始化父類構建函授
logs_obj.info('------- 啟動瀏覽器 -------')
# 難點,頁面銜接
elements=ElementDataUtils('main', 'main_page').get_element_info()
self.company_name_show_box=elements['company_name_show_box']
self.my_zone_menu=elements['my_zone_menu']
self.my_product_menu=elements['my_product_menu']
self.my_project_menu=elements['my_project_menu']
self.my_qa_menu=elements['my_qa_menu']
self.username_show_box=elements['username_show_box']
self.quit_button=elements['quit_button']
def get_company_name(self):
self.get_attribute(self.company_name_show_box)
def goto_myzone(self):
self.click(self.my_zone_menu)
def goto_product(self):
self.click(self.my_product_menu)
def goto_project(self):
self.click(self.my_project_menu)
def goto_qa(self):
self.click(self.my_qa_menu)
def get_username(self):
text=self.get_text_value(self.username_show_box)
return text
def click_username_button(self):
self.click(self.username_show_box)
def click_quit_button(self):
self.click(self.quit_button)
if __name__=='__main__':
driver=Browser().get_driver()
LoginPage_obj=LoginPage(driver)
main_page_obj=MainPage(driver)
main_page_obj.open_url('http://47.107.178.45/zentao/www/index.php?m=user&f=loginz')
main_page_obj.set_browser_max()
# 登錄
LoginPage_obj.input_username('test01')
LoginPage_obj.input_password('newdream123')
LoginPage_obj.click_login()
# 點擊我的,項目,產品,
main_page_obj.get_company_name()
main_page_obj.get_username()
main_page_obj.goto_myzone()
main_page_obj.goto_project()
main_page_obj.goto_product()
main_page_obj.goto_qa()
main_page_obj.click_username_button()
main_page_obj.click_quit_button()
LoginPage_obj.quit_driver()
產品信息元素類,product_page.py暫未補充代碼。
qa頁面元素類,create_bug_page.py
# @desc 提bug元素和動作頁面
from common.base_page import BasePage
from common.browser import Browser
from common.log_utils import logs_obj
from common.element_data_utils import ElementDataUtils
from element_info.login.login_page import LoginPage
from element_info.main.main_page import MainPage
class CreateBUGPage(BasePage):
def __init__(self,driver):
# 元素識別分離
super().__init__(driver) # 初始化父類構建函授
logs_obj.info('------- 啟動瀏覽器 -------')
# 難點,頁面銜接
elements=ElementDataUtils('qa', 'create_bug_page').get_element_info()
self.bug_module_link=elements['bug_module_link']
self.commit_bug_link=elements['commit_bug_link']
self.product_selects=elements['product_selects']
self.Ecommerce_projects_select=elements['Ecommerce_projects_select']
self.module_box_selects=elements['module_box_selects']
self.customer_center_select=elements['customer_center_select']
self.bug_errors_selects=elements['bug_errors_selects']
self.page_error_select=elements['page_error_select']
self.bug_os_selects=elements['bug_os_selects']
self.windows_select=elements['windows_select']
self.bug_browser_selects=elements['bug_browser_selects']
self.chrome_select=elements['chrome_select']
self.edition_selects=elements['edition_selects']
self.v1_0_select=elements['v1_0_select']
self.loadAllUsers_button=elements['loadAllUsers_button']
self.assignedTo_selects=elements['assignedTo_selects']
self.LanShu_select=elements['LanShu_select']
self.deadline_input=elements['deadline_input']
self.bug_title_input=elements['bug_title_input']
self.severity_selects=elements['severity_selects']
self.two_severity_select=elements['two_severity_select']
self.pri_selects=elements['pri_selects']
self.two_pri_select=elements['two_pri_select']
self.report_steps_iframe=elements['report_steps_iframe']
self.report_steps_body=elements['report_steps_body']
self.storyIdBox_span=elements['storyIdBox_span']
self.upload_file_button=elements['upload_file_button']
self.submit_button=elements['submit_button']
# 點擊主頁面測試 --->
def click_bug_module_link(self):
self.click(self.bug_module_link)
# 點擊提bug按鈕
def click_commit_bug_link(self):
self.click(self.commit_bug_link)
def get_commit_bug_text(self):
bug_text=self.get_text_value(self.commit_bug_link)
return bug_text
# 激活系統存在的產品
def click_product_selects(self):
self.click(self.product_selects)
# 選擇電商項目產品項
def click_Ecommerce_projects_select(self):
self.click(self.Ecommerce_projects_select)
# 激活產品模塊
def click_module_selects(self):
self.click(self.module_box_selects)
# 選擇/后臺-客戶中心模塊
def click_customer_center_select(self):
self.click(self.customer_center_select)
# 激活bug錯誤類型下拉框
def click_bug_selects(self):
self.click(self.bug_errors_selects)
# 點擊界面錯誤項
def click_page_error_select(self):
self.click(self.page_error_select)
# 激活bug系統錯誤類型
def click_bug_os_selects(self):
self.click(self.bug_os_selects)
# 選擇bug錯誤類型:windows
def click_bug_windows_select(self):
self.click(self.windows_select)
# 激活bug屬于什么瀏覽器錯誤
def click_bug_browser_selects(self):
self.click(self.bug_browser_selects)
# 選擇屬于chrome 瀏覽器
def click_chrome_select(self):
self.click(self.chrome_select)
# 點擊版本下拉框
def click_edition_selects(self):
self.click(self.edition_selects)
# 選擇v1.0版本
def click_v1_0_select(self):
self.click(self.v1_0_select)
# 點擊加載所有用戶按鈕
def click_loadAllUsers(self):
self.click(self.loadAllUsers_button)
# 激活指派人下拉列表
def click_assignedTo_selects(self):
self.click(self.assignedTo_selects)
# 選擇指派人蘭輸
def click_LanShu_select(self):
self.click(self.LanShu_select)
# 輸入截至日期:'2022-08-08'
def input_deadline(self,deadline):
self.send_keys(self.deadline_input,deadline )
# 輸入bug標題:'人才中心-新增接口404'
def input_bug_title(self,bug_title):
self.send_keys(self.bug_title_input, bug_title)
# 激活嚴重等級下拉框
def click_severity_selects(self):
self.click(self.severity_selects)
# 選擇嚴重程度2選項
def click_two_severity_select(self):
self.click(self.two_severity_select)
# 激活優先級下拉框
def click_pri_selects(self):
self.click(self.pri_selects)
# 選擇嚴重程度2選項
def click_two_pri_select(self):
self.click(self.two_pri_select)
# 切入重現步驟框架中
def enter_report_steps_iframe(self):
self.switch_to_frame(element_info=self.report_steps_iframe)
# 清空重現步驟內容
def clear_report_steps_body(self):
self.clear(self.report_steps_body)
# 輸入重現步驟內容:'[步驟]:1.登錄成功后。2.點擊人才中心。3.點擊新增按鈕。4.輸入內容,點擊保存按鈕。.\n\n'
# '[結果]:點擊保存提示:"system error".\n\n'
# '[期望]:點擊保存提示:"保存成功"'
def input_report_steps_body(self,report_steps_content):
self.send_keys(self.report_steps_body,report_steps_content)
# 激活相關需求
def click_storyBox_span(self):
self.click(self.storyIdBox_span)
# 點擊上傳文件按鈕
def click_upload_file_button(self):
self.click(self.upload_file_button)
# 點擊提交按鈕
def click_submit_button(self):
self.click(self.submit_button)
if __name__=='__main__':
driver=Browser().get_driver()
LoginPage_obj=LoginPage(driver)
main_page_obj=MainPage(driver)
create_bug_page_obj=CreateBUGPage(driver)
main_page_obj.open_url('http://47.107.178.45/zentao/www/index.php?m=user&f=loginz')
main_page_obj.set_browser_max()
# 登錄
LoginPage_obj.input_username('test01')
LoginPage_obj.input_password('newdream123')
LoginPage_obj.click_login()
main_page_obj.goto_qa()
create_bug_page_obj.click_bug_module_link()
# create_bug_page_obj.click_commit_bug_link()
print(create_bug_page_obj.get_commit_bug_text())
動作層,目錄結構如下圖:
login_action.py
# -- coding: utf-8 --
# @Time : 2022/7/22 17:13
# @Author : siyu.yang
# @File : login_action.py
# @Software: PyCharm
# @desc: 功能層
from element_info.login.login_page import LoginPage
from element_info.main.main_page import MainPage
from common.config_utils import config_obj
class LoginAction():
def __init__(self, driver):
self.login_page=LoginPage(driver)
# 登錄操作
def login_action(self, username, password):
self.login_page.input_username(username)
self.login_page.input_password(password)
self.login_page.click_login()
def login_success(self, username, password):
self.login_action(username, password)
return MainPage(self.login_page.driver)
def login_fail(self, username, password):
self.login_action(username, password)
return self.login_page.get_login_fail_alert_content()
# 默認登錄
def default_login(self):
self.login_action(config_obj.user_name, config_obj.pass_word)
return MainPage(self.login_page.driver)
# 擴展:
def login_by_cookie(self):
pass
main_action.py
# @desc: 主頁面業務類
from element_info.login.login_page import LoginPage
from element_info.main.main_page import MainPage
class MainPageAction():
def __init__(self, driver):
self.main_page=MainPage(driver)
# 登錄-進入我的地盤-退出
def goto_myzone_quit(self):
self.main_page.goto_myzone()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主頁面
# 登錄-點擊我的項目-退出
def goto_project_quit(self):
self.main_page.goto_project()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主頁面
# 登錄-點擊我的產品-退出
def goto_product_quit(self):
self.main_page.goto_product()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主頁面
#登錄-獲取當前登錄的用戶-退出
def get_username_quit(self):
self.main_page.get_username()
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver) # 退出操作返回主頁面
quit_action.py
from element_info.main.main_page import MainPage
from element_info.login.login_page import LoginPage
class QuitAction():
def __init__(self, driver):
self.main_page=MainPage(driver)
def quit_action(self):
self.main_page.click_username_button()
self.main_page.click_quit_button()
return LoginPage(self.main_page.driver)
create_bug_action.py
# -- coding: utf-8 --
# @Time : 2022/7/22 17:54
# @Author : siyu.yang
# @File : create_bug_action.py
# 可以把操作封裝成功能函數也行
from element_info.qa.create_bug_page import CreateBUGPage
from actions.main_action import MainPage
import os
class CreateBugAction():
def __init__(self, driver):
self.bug_page=CreateBUGPage(driver)
def commit_bug_action(self, deadline, bug_title, report_steps_content):
'''
提bug
:param deadline: 截至日期
:param bug_title: bug的標題
:param report_steps_content: 重現步驟
:return:
'''
self.bug_page.click_bug_module_link()
self.bug_page.click_commit_bug_link()
self.bug_page.click_product_selects()
self.bug_page.click_Ecommerce_projects_select()
self.bug_page.wait(1)
self.bug_page.click_module_selects()
self.bug_page.click_customer_center_select()
self.bug_page.wait(1)
self.bug_page.click_bug_selects()
self.bug_page.click_page_error_select()
self.bug_page.click_bug_os_selects()
self.bug_page.click_bug_windows_select()
self.bug_page.click_bug_browser_selects()
self.bug_page.click_chrome_select()
self.bug_page.click_edition_selects()
self.bug_page.click_v1_0_select()
self.bug_page.wait(1)
self.bug_page.click_loadAllUsers()
self.bug_page.wait(1)
self.bug_page.click_assignedTo_selects()
self.bug_page.wait(1)
self.bug_page.click_LanShu_select()
self.bug_page.wait(1)
self.bug_page.input_deadline(deadline)
self.bug_page.input_bug_title(bug_title)
self.bug_page.click_severity_selects()
self.bug_page.click_two_severity_select()
self.bug_page.click_pri_selects()
self.bug_page.click_two_pri_select()
self.bug_page.enter_report_steps_iframe()
self.bug_page.clear_report_steps_body()
self.bug_page.input_report_steps_body(report_steps_content)
self.bug_page.switch_to_frame()
self.bug_page.switch_to_default_content()
self.bug_page.scroll(150)
self.bug_page.click_storyBox_span()
self.bug_page.click_upload_file_button()
os.system('E:/auto3_script/up.exe')
self.bug_page.scroll(100)
self.bug_page.click_submit_button()
return MainPage(self.bug_page.driver)
testcase層,目錄結果如下圖:
login_case.py
# -- coding: utf-8 --
# @Time : 2022/7/22 17:57
# @Author : siyu.yang
# @File : login_case.py
# @Software: PyCharm
import unittest
from actions.login_action import LoginAction
from common.selenium_base_case import SeleniumBaseCase
from common.test_data_utils import TestDataUtils
class LoginCase(SeleniumBaseCase):
test_class_data=TestDataUtils('login_suit', 'login_case', 'LoginCase').convert_exceldata_to_testdata()
def setUp(self):
super().setUp()
print('LoginCase 測試類初始化父類')
# self.test_class_data=TestDataUtils('login_suit', 'LoginCase').convert_exceldata_to_testdata()
#
@unittest.skipIf(test_class_data['test_login_success'].get('isnot'), reason='如果條件為真,就執行改用例')
def test_login_success(self):
test_function_data=self.test_class_data['test_login_success']
login_action=LoginAction(self.base_page.driver)
login_action=login_action.login_success(test_function_data['test_parameter'].get('username'),
test_function_data['test_parameter'].get('password'))
actual=login_action.get_username()
self.assertEqual(actual, test_function_data['expected_result'], 'test01,登錄失敗')
@unittest.skipIf(test_class_data['test_login_fail_case'].get('isnot'), reason='如果條件為真,就執行改用例')
def test_login_fail(self):
test_function_data=self.test_class_data['test_login_fail_case']
login_action=LoginAction(self.base_page.driver)
actual=login_action.login_fail(test_function_data['test_parameter'].get('username'),
test_function_data['test_parameter'].get('password'))
self.assertEqual(actual, test_function_data['expected_result'])
if __name__=='__main__':
unittest.main()
quit_case.py
import unittest
from actions.login_action import LoginAction
from actions.quit_action import QuitAction
from common.selenium_base_case import SeleniumBaseCase
from common.test_data_utils import TestDataUtils
class QuitCase(SeleniumBaseCase):
test_class_data=TestDataUtils('main_suit', 'quit_case', 'QuitCase').convert_exceldata_to_testdata()
def setUp(self):
super().setUp()
print('LoginCase 測試類初始化父類')
@unittest.skipIf(test_class_data['test_quit_success'].get('isnot'), reason='如果條件為真,就執行改用例')
def test_quit_success(self):
test_function_data=self.test_class_data['test_quit_success']
"""正常退出操作"""
login_action=LoginAction(self.driver)
main_page=login_action.default_login()
quit_action=QuitAction(main_page.driver)
login_page=quit_action.quit_action() # 退出后返回主頁面
actual=login_page.get_title()
self.assertEqual(actual.__contains__('用戶登錄'), True)
if __name__=='__main__':
unittest.main()
commit_bug_case.py
import unittest
from actions.login_action import LoginAction
from actions.create_bug_action import CreateBugAction
from common.selenium_base_case import SeleniumBaseCase
from common.test_data_utils import TestDataUtils
class CreateBugSuit(SeleniumBaseCase):
test_bug_class_data=TestDataUtils('qa_suit', 'qa_case', 'CreateBugSuit').convert_exceldata_to_testdata()
def setUp(self):
super().setUp()
print('LoginCase 測試類初始化父類')
# self.test_bug_class_data=TestDataUtils('bug_suit', 'CreateBugSuit').convert_exceldata_to_testdata()
@unittest.skipIf(test_bug_class_data['test_commit_bug_success'].get('isnot'), reason='如果條件為真,就執行改用例')
def test_commit_bug_success(self):
"""正常提交bug操作"""
test_function_data=self.test_bug_class_data['test_commit_bug_success']
login_action=LoginAction(self.base_page.driver)
main_page=login_action.default_login()
main_page.goto_qa()
bug_page=CreateBugAction(main_page.driver)
bug_page.commit_bug_action(test_function_data['test_parameter'].get('deadline'),
test_function_data['test_parameter'].get('bug_title'),
test_function_data['test_parameter'].get('report_steps_content'))
actual_result=main_page.get_title()
self.assertEqual(actual_result.__contains__(test_function_data['expected_result']), True)
if __name__=='__main__':
unittest.main()
screen_shot 截圖圖片層
test_data測試數據層,目錄結構如下圖;
其中login_case.xlsx內容為,其它頁面內容相似:
runner 運行層,run_all_case.py
import os, unittest
import shutil
import sys
sys.path.append('C:\\Users\\kcadmin\\Desktop\\python code\\PO_UI_Test_Framework')
from common import HTMLTestReportCN
from common.config_utils import config_obj
from common.email_utils import EmailUtils
current_path=os.path.dirname(__file__)
case_path=os.path.join(current_path, '..', config_obj.case_path)
report_path=os.path.join(current_path, '..', config_obj.report_path)
class RunAllCase:
def __init__(self):
self.test_case=case_path
self.report_path=report_path
self.title="禪道UI自動化測試報告"
self.description="禪道UI自動化測試報告"
def run(self):
discover=unittest.defaultTestLoader.discover(start_dir=self.test_case,
pattern='*_case.py',
top_level_dir=self.test_case)
all_suit=unittest.TestSuite()
all_suit.addTest(discover)
report_dir=HTMLTestReportCN.ReportDirectory(self.report_path)
report_dir.create_dir(self.title)
dir_path=HTMLTestReportCN.GlobalMsg.get_value('dir_path')
report_path=HTMLTestReportCN.GlobalMsg.get_value('report_path')
fp=open(report_path, 'wb')
runner=HTMLTestReportCN.HTMLTestRunner(stream=fp,
title=self.title,
description=self.description,
tester='YangShiYu')
runner.run(all_suit)
fp.close()
return dir_path
if __name__=='__main__':
dir_path=RunAllCase().run() #運行所有用例
#將生成的測試報告打包成zip文件,并發送郵件
# shutil.copytree(dir_path,sys.argv[1])
smtp_body='禪道UI自動化測試報告,請注意查收!'
send_email_obj=EmailUtils(smtp_body, dir_path).zip_send_mail()
最后運行run_all_case.py,會自動生產測試報告和產生日志文件,且對應的郵件也會收到運行的測試報告
*請認真填寫需求信息,我們會在24小時內與您取得聯系。