Selenium Web自動化測試框架實踐
阿新 • • 發佈:2020-11-04
專案背景
https://passport.csdn.net/login CSDN登入頁面
功能實現
- 自動執行用例
- 自動生成測試報告
- 自動斷言與截圖
- 自動將最新測試報告發送到指定郵箱
- PageObject+Unittest+ddt資料驅動用例
- 執行日誌、分散式執行
專案架構
瀏覽器driver定義
from common.readFile import ReadFile from common.logger import Logger from selenium import webdriver logger = Logger() from selenium.webdriver importRemote class Browser(): def __init__(self): config = ReadFile() self.browser = config.readConfig("Browser", "browser") self.host = config.readConfig("host","host") logger.info("You had select {} host {} browser.".format(self.host,self.browser)) def driver(self):""" 啟動瀏覽器驅動 :return: 返回瀏覽器驅動URL """ try: # driver = webdriver.Chrome() driver = Remote(command_executor='http://' + self.host + '/wd/hub', desired_capabilities={ 'platform': 'ANY','browserName': self.browser, 'version': "", 'javascriptEnabled': True } ) return driver except Exception as msg: print("驅動異常-> {0}".format(msg))
用例執行前後的環境準備工作
import unittest from common.driver import Browser class StartEnd(unittest.TestCase): def setUp(self): self.driver = Browser().driver() self.driver.implicitly_wait(10) self.driver.maximize_window() def tearDown(self): self.driver.quit()
工具方法模組
主要封裝一些公共的方法如:截圖,查詢最新報告
import time from selenium import webdriver import os,sys sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) from config import setting def inser_img(driver): # 指定截圖存放的根目錄路徑 screen_dir = setting.TEST_REPORT + '/imges/' rq = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) screen_name = screen_dir + rq + '.png' driver.get_screenshot_as_file(screen_name) print('screenshot:' + screen_name) #查詢最新的測試報告 def latest_report(report_dir): lists = os.listdir(report_dir) lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn)) file = os.path.join(report_dir, lists[-1]) return file def latest_report_img(report_dir): lists = os.listdir(report_dir) lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn)) file = os.path.join(report_dir, lists[-1]) return file
Pageobject頁面物件封裝
基礎頁面類
import time from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from common.logger import Logger from common.readFile import ReadFile logger = Logger() class BasePage(): "定義一個頁面基類,讓所有頁面都繼承這個類,封裝一些常用的頁面操作方法到這個類" def __init__(self, driver): self.driver = driver config = ReadFile() self.baseurl = config.readConfig("BaseUrl", "url") def open_url(self, url): self.driver.get(self.baseurl + url) # 退出瀏覽器 def quit_browser(self): self.driver.quit() # 瀏覽器前進操作 def forward(self): self.driver.forward() # 瀏覽器後退操作 def back(self): self.driver.back() # 隱式等待 def wait(self, seconds): self.driver.implicitly_wait(seconds) # 查詢元素 def find_element(self, selector): selector_by = selector['find_type'] selector_value = selector['element_info'] try: if selector_by == 'id': el = self.driver.find_element_by_id(selector_value) elif selector_by == "n" or selector_by == 'name': el = self.driver.find_element_by_name(selector_value) elif selector_by == 'cs' or selector_by == 'css_selector': el = self.driver.find_element_by_css_selector(selector_value) elif selector_by == 'cn' or selector_by == 'classname': el = self.driver.find_element_by_class_name(selector_value) elif selector_by == "lt" or selector_by == 'link_text': el = self.driver.find_element_by_link_text(selector_value) elif selector_by == "plt" or selector_by == 'partial_link_text': el = self.driver.find_element_by_partial_link_text(selector_value) elif selector_by == "tn" or selector_by == 'tag_name': el = self.driver.find_element_by_tag_name(selector_value) elif selector_by == "x" or selector_by == 'xpath': el = self.driver.find_element_by_xpath(selector_value) elif selector_by == "ss" or selector_by == 'selector_selector': el = self.driver.find_element_by_css_selector(selector_value) else: raise NameError("Please enter a valid type of targeting elements.") except NoSuchElementException : logger.error("{0}頁面中未能找到{1}元素".format(self, selector_value)) return el # 輸入 def input(self, selector, text): el = self.find_element(selector) try: el.clear() el.send_keys(text) logger.info("Had type \' %s \' in inputBox" % text) except NameError as e: logger.error("Failed to type in input box with %s" % e) # 點選 def click(self, selector): el = self.find_element(selector) try: logger.info("The element \' %s \' was clicked." % el.text) el.click() except NameError as e: logger.error("Failed to click the element with %s" % e) @staticmethod def sleep(seconds): time.sleep(seconds) logger.info("Sleep for %d seconds" % seconds) def get_text(self,selector): el = self.find_element(selector) try: return el.text except NameError as e: logger.error("Failed to text the element with %s" % e) def switch_frame(self, selector): """ 多表單巢狀切換 :param loc: 傳元素的屬性值 :return: 定位到的元素 """ try: el = self.find_element(selector) return self.driver.switch_to_frame(el) except NoSuchElementException as e: logger.error("查詢iframe異常-> {0}".format(e)) def switch_windows(self, selector): """ 多視窗切換 :param loc: :return: """ try: el = self.find_element(selector) return self.driver.switch_to_window(el) except NoSuchElementException as e: logger.error("查詢視窗控制代碼handle異常-> {0}".format(e)) def switch_alert(self): """ 警告框處理 :return: """ try: return self.driver.switch_to_alert() except NoSuchElementException as e: logger.error("查詢alert彈出框異常-> {0}".format(e))
LoginPage.py —— CNDS登入頁面
from pageObject.basePage import * from selenium import webdriver from common.readFile import ReadFile from config import setting login_el = ReadFile().readYaml(setting.TEST_Element_YAML + '/' + 'login.yaml') data = ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml') class CndsPage(BasePage): '''登入頁面''' url = '/login' # 定位器,通過元素屬性定位元素物件 #選擇賬號密碼登入 chanlelogin_loc = login_el['testcase'][0] # 賬號輸入框 username_loc = login_el['testcase'][1] # 密碼輸入框 pwd_loc = login_el['testcase'][2] # 單擊登入 login_accout_loc = login_el['testcase'][3] def accout_login(self,accout,passwd): self.open_url(self.url) self.click(self.chanlelogin_loc) self.input(self.username_loc,accout) self.input(self.pwd_loc,passwd) self.click(self.login_accout_loc) # 定位器,通過元素屬性定位檢查項元素物件 user_login_success_loc = login_el['check'][0] accout_id_loc = login_el['check'][1] accout_pawd_error_loc = login_el['check'][2] # 賬號或密碼錯誤提示 def accout_passwd_error(self): return self.get_text(self.accout_pawd_error_loc) # 登入成功,跳轉到個人資料頁,獲取使用者名稱 def get_account(self): self.click(self.user_login_success_loc) time.sleep(2) def user_login_success(self): return self.find_element(self.accout_id_loc).text
組織測試用例
- 使用者名稱密碼正確點選登入
- 使用者名稱正確,密碼錯誤點選登入
import unittest from common import function,myUnit,readFile from pageObject.loginPage import CndsPage from time import sleep from common.logger import Logger from config import setting import ddt log = Logger() testData= readFile.ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml') @ddt.ddt class LoginTest(myUnit.StartEnd): # @unittest.skip('skip this case') """CNDS登入測試""" def user_login_verify(self,account,passwd): """ 使用者登入 :param :account 賬號 :param passwd: 密碼 :return: """ CndsPage(self.driver).accout_login(account,passwd) @ddt.data(*testData) def test_login_normal(self,datayaml): log.info("test_login1_normal is start run...") self.user_login_verify(datayaml['data']['accout'],datayaml['data']['passwd']) sleep(3) #斷言與截圖 po = CndsPage(self.driver) if datayaml['screenshot'] == 'login_success': po.get_account() function.inser_img(self.driver) self.assertEqual(po.user_login_success(), datayaml['check'][0], "登入成功,返回實際結果是->: {0}".format(po.user_login_success())) else: function.inser_img(self.driver) self.assertEqual(po.accout_passwd_error(), datayaml['check'][0],"登入失敗,返回實際結果是->: {0}".format(po.accout_passwd_error())) print("test_login1_normal is test end!")
執行測試用例
import unittest from common.function import latest_report from common.sendMail import * from config import setting from thridLib.HTMLTestRunner import HTMLTestRunner import time import os,sys sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) report_dir = setting.TEST_REPORT + '/report/' def add_case(test_path=setting.TEST_DIR): discover = unittest.defaultTestLoader.discover(test_path, pattern="test*.py") return discover def run_case(all_case,result_path=report_dir): print("start run testcase...") now = time.strftime("%Y-%m-%d %H_%M_%S") report_name = result_path + '/' + now + 'result.html' print("start write report...") #HTMLTestRunner測試報告 with open(report_name, 'wb') as f: runner = HTMLTestRunner(stream=f, title='測試報告', description='用例執行情況') # 定義測試報告 runner.run(all_case) # 執行測試用例 f.close() print("find latest report...") # 查詢最新的測試報告 report = latest_report(result_path) # 郵件傳送報告 print("send email report...") send_mail(report) print("test end!") if __name__ == '__main__': cases = add_case() run_case(cases)
詳細可到git地址: