整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          自動化測試之HTML測試報告

          自動化測試之HTML測試報告

          載地址HTMLTestRunner.py文件:

          http://tungwaiyip.info/software/HTMLTestRunner.html

          下載的適合python2,如果python3要修改一些內容

          首先吧HTMLTestRunner文件添加到環境變量里,可以直接放到python的Lib目錄下

          HTMLTestRunner是python標準庫unittest單元測試框架的一個擴展,用于生成HTML測試報告


          生成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 是用來描述網頁的一種語言。HTML 是一種在 Web 上使用的通用標記語言。HTML 允許你格式化文本,添加圖片,創建鏈接、輸入表單、框架和表格等等,并可將之存為文本文件,瀏覽器即可讀取和顯示。

          • HTML 指的是超文本標記語言: HyperText Markup Language
          • HTML 不是一種編程語言,而是一種標記語言
          • 標記語言是一套標記標簽 (markup tag)
          • HTML 使用標記標簽來描述網頁
          • HTML 文檔包含了HTML 標簽文本內容
          • HTML文檔也叫做 web 頁面

          2 入門實例

          新建一個test.html文件,內容如下

          <!DOCTYPE html><html><head><meta charset="utf-8"><title>ZONGXP</title></head><body> <h1>我的第一個標題</h1><p>我的第一個段落。</p> </body></html>

          其中:

          • <!DOCTYPE html> 聲明為 HTML5 文檔
          • <html> 元素是 HTML 頁面的根元素
          • <head> 元素包含了文檔的元(meta)數據,如 <meta charset="utf-8"> 定義網頁編碼格式為 utf-8(由于在大部分瀏覽器中直接輸出中文會出現亂碼,所以要在頭部將字符聲明為UTF-8
          • <title> 元素描述了文檔的標題
          • <body> 元素包含了可見的頁面內容
          • <h1> 元素定義一個大標題
          • <p> 元素定義一個段落

          保存后運行,即可在瀏覽器中打開如下界面

          3 各部分詳解

          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 速查列表

          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,會自動生產測試報告和產生日志文件,且對應的郵件也會收到運行的測試報告


          主站蜘蛛池模板: 日韩在线一区视频| 91福利国产在线观看一区二区| 国产高清视频一区三区| 亚洲欧洲一区二区三区| 精品国产AV一区二区三区| 骚片AV蜜桃精品一区| 91精品福利一区二区| 久久精品黄AA片一区二区三区| 国产伦精品一区二区三区女| 亚洲色无码专区一区| 日韩精品一区二区三区国语自制 | 91精品乱码一区二区三区| 91video国产一区| 另类ts人妖一区二区三区| chinese国产一区二区| 国99精品无码一区二区三区| 91video国产一区| 一区二区日韩国产精品| 亚洲AV成人一区二区三区AV| 亚洲欧美日韩中文字幕在线一区| 波多野结衣中文字幕一区| 国产成人一区二区三区视频免费| 无码精品尤物一区二区三区| 波多野结衣一区二区三区高清在线| 国产AⅤ精品一区二区三区久久 | 少妇特黄A一区二区三区| 精品无码一区二区三区在线| 国产一国产一区秋霞在线观看| 国产精品无码一区二区三级 | 午夜无码一区二区三区在线观看| 日韩一区二区三区在线观看| 国产一区二区中文字幕| 国产99久久精品一区二区| 精品久久久中文字幕一区| 午夜天堂一区人妻| 亚洲一区二区三区无码影院| 亚洲中文字幕乱码一区| 国产一区二区电影在线观看| 欧洲精品一区二区三区| 亚洲一区在线视频| 中文字幕无码一区二区免费|