Web項目的 UI 自動化測試方案
有用的鏈接:
- 自動化Selenium的Python文檔
http://www.lxweimin.com/p/4ce5ecef5f6c - 自動化Selenium的Java文檔
http://www.lxweimin.com/p/00616647ddae - 自動化Selenium的源代碼
https://coding.net/u/lintyleo/p/ProSelenium/git
項目討論
- 項目中符合自動化測試的部分有哪些?(目標和范圍 scope, 準入準出標準)
- 穩定的需求點、變動較少的頁面
- 每日構建后的測試驗證 daily build
- 比較頻繁的回歸測試
- 需要在多平臺上運行的相同測試案例、組合遍歷型的測試、大量的重復任務
- 自動化用例在整個項目的測試用例的覆蓋率
- 一般的要求 50% +
- 重點的要求 80% +
- 根據項目的具體要求,變動特別大的項目需要額外單獨考慮覆蓋率
團隊建設
建立自動化測試的組,理想狀態下有4個人員,測試開發、中高級自動化測試工程師、2個初級自動化工程師;非理想的情況下,可能只有一個人。
-
測試開發:
基礎答案
:自動化框架的建設,確定自動化框架的設計模式、第三方代碼工具的封裝、中間公共模塊的設計和調用、測試用例、測試套件的管理和執行、測試報告和測試結果的輸出(文件輸出和郵件通知)可選高級
:如果可能的話,需要搭建持續集成服務器(CI,Continuous Integration Server)的環境,進行持續交付和自動化的冒煙測試等。培訓的任務,需要將設計的框架以及封裝的驅動,對其他成員進行培訓。
有自動化方案的實施經驗、有開發背景、以及持續集成的背景等。
-
中高級自動化測試工程師:
配合測試開發人員,實施測試框架的建設。主要負責中間公共模塊的實現和實例化等,以及部分高難度和流程復雜的自動化用例腳本編寫和調試等工作。
有參與過自動化方案的建設、腳本編寫經驗豐富、會代碼調試、懂Web測試等。
初級自動化測試工程師:
根據中間公共模塊的設計,進行實例化公共模塊、方法組合,實現自動化用例腳本的編寫。
有計算機編程思維、有代碼經驗、可以讀懂腳本和HTML等。若只有我一個人:
首先實現自動化用例的維護和執行。在這個基礎上不斷的抽取實現公共模塊的設計以及測試報告的生成等工作。通過經驗的積累,以及后續人員的補充,早日做好自動化框架的建設工作。
技術方案
Selenium WebDriver、Python(unittest) Java(JUnit)、CI Server
技術方案:
選擇Python + Selenium
的技術方案。
首先技術工具是免費的,Python的工具用PyCharm
社區版,Selenium的WebDriver
是開源工具。利用比較簡潔的Python語言進行自動化測試,對于人員的學習成本來講比較實用,學習時間短,有優勢。
另外Python自帶的unittest
單元測試框架可以很方便的實現自動化用例的設計和執行以及自動化用例套件的管理等任務。Python是純面向對象的語言,后續也可以過渡到Java + Selenium
進行更加豐富的自動化測試。
此外,可以選擇Jenkins
作為持續集成服務器,配合Python+Selenium的方案進行自動化冒煙測試。
源代碼管理工具(VCS, version control system)
選擇SVN(git)作為代碼的源代碼管理工具。集成在PyCharm中的步驟如下
- 把代碼放到SVN在本地簽出(check out)的文件夾目錄中,例如
D:\SVN\XXProject\Trunck
- 用PyCharm打開 剛剛部署的代碼
- 選擇PyCharm的 VCS|Enable VCS integration,選擇 Subversion(svn) 或者 Git
- 右鍵項目文件的根目錄,選擇 Subversion | add to VCS
- 右鍵項目文件的根目錄,或者選 VCS | Commit Directory...
- 每天打開代碼后,首先 Subversion | update project
硬件:
硬件的要求不高,主要需要獨立的測試環境。另外測試人員用的電腦最好是Windows桌面操作系統,需要安裝Firefox瀏覽器,避免47.0的最新版本。測試人員最好也使用Chrome瀏覽器輔助進行Web元素的定位。
Selenium 學習總結
Selenium IDE (火狐的插件)
- Selenium IDE
一個基于火狐瀏覽器的插件- 錄制(需要確保右上角的錄制按鈕是按下去的),為了我們熟悉Selenium WebDriver/ RC
- 保存和另存為測試用例
- 無論是否保存用例,都可以直接回放
-
- 導出測試用例的對應的編程腳本
-
C#
Nunit
WebDriver -
Java
Junit
/testNG
WebDriver -
Python
unittest
WebDriver -
Ruby
Test::Unit
WebDriver
- 插入、編輯、刪除命令
- 學習Selenium的WebDriver/ RC
Python + Selenium WebDriver
- 搭建環境步驟
a 安裝 python3.x (windows xp 不支持 python3.5+)
b 設置環境變量 path(安裝時候也可以解決 勾上 add python.ext to path)
c 安裝Selenium 用pip命令安裝 pip install -U selenium
有無問題?- 路徑,pip可能定位不到,pip也可能定位到別的文件夾(perl)
方案:cd c:\python34\scripts - 外網ip問題。交換機的原因,局域網里面是同一個ip,造成安裝超時
- 火狐的版本 46.0以及以下
- windows 7 x64以上的系統,需要用管理員模式運行cmd,否則會安裝失敗。
- 路徑,pip可能定位不到,pip也可能定位到別的文件夾(perl)
- 普通的使用
定位方式
by id
,name
,class_name
,tag_name
,css_selector
,xpath
,link_text
,partial_link_text
主要用的 是 id,name, css_selector, xpath, link_text
Selenium 基本使用
Python + Selenium 環境搭建
-
安裝Python,3.x(3.4 3.5 3.6)
注意:環境變量path
需要添加 "C:\Python34;C:\Python34\Scripts;"到Path
步驟:- 右鍵
我的電腦
屬性 |高級系統設置
|環境變量
- 找
系統變量
|Path
并 雙擊 |Ctrl+C
| 編輯 |Ctrl+V
- 右鍵
-
安裝 Selenium
cmd |pip install -U selenium
-U
=--upgrade
升級安裝類似于linux命令
command -x param
容易出現的問題- 環境變量
cd C:\Python34\Scripts
再安裝 - 管理員權限
右鍵管理員方式運行
- 環境變量
WebDriver的基本使用
-
實例化一個WebDriver的對象(使用默認的火狐瀏覽器 v46或者以下)
driver = webdriver.Firefox()注意,一定要寫括號,代表實例化對象
打開網址
driver.get("http://localhost/ranzhi/www")查找元素
用id : driver.find_element_by_id("account")
用name: driver.find_element_by_name("password")
用xpath css_selector
對元素的操作
clear()
click()
send_keys()使用python的休眠,給瀏覽器留出時間加載頁面
sleep(2)關閉退出火狐
driver.quit()
selenium WebDriver的進階操作
-
unittest 單元測試框架的使用
驗證:斷言
self.assertEqual(expected, actual, msg)
管理測試用例: 每一個以
test_
開頭的方法可以在自動化測試用例中忽略的部分: 編號 名稱 優先級 模塊(項目) ## 忽略 必須在自動化用例中強調的部分: 前置條件 setUp() 輸入數據 步驟 test_ 開頭的方法 預期結果 test_ 開頭的方法 清理 tearDown()
新增的一個知識點: 測試的初始化 以及 測試的結束
setUpClass() 和 tearDownClass()
注意 上述方法 與 setUp() 和 tearDown() 的調用順序
-
定位方式的使用
-
css_selector
方法調用:
driver.find_element_by_css_selector("#langs > button")
?
CSS的3種選擇器:
- id: 使用
#+id
- tag: 使用
tag
- class: 使用
.+class
CSS selector的獲取
可以使用開發者工具,定位的元素,右鍵 | 復制 selector(復制CSS路徑)
- Chrome使用了相對路徑
#langs > button
- Firefox(firebug)使用了絕對路徑
html.screen-desktop-wide.device-desktop body.m-user-login div.container div#login div.panel-head div.panel-actions div#langs.dropdown.open button.btn
- id: 使用
-
class_name
通過 class定位元素,必須保持 class唯一,否則定位會失敗
driver.find_element_by_class_name("btn")
?
-
-
link_text 和 partial_link_text
- 文字選擇正確就行了
-
xpath
- chrome內核的開發者工具,復制的是相對的xpath
- firefox內核的開發者工具(firebug),復制的絕對的xpath
?
-
特定的元素的處理
-
frame
<iframe> <html> <head></head> <body> <我們需要定位的元素> </body> </html> </iframe>
上述代碼中,我們需要定位的元素,處于 一個frame中:我們需要先切換到對應的frame中,然之操作,之后再退出
## 我們需要先切換到對應的frame中 ## 切換frame driver.switch_to.frame("frame_name") ## 或者用保險的辦法切換frame frame_element = driver.find_element_by_css_selector("#frame_id") driver.switch_to.frame(frame_element) ## 開始做定位操作 ## <-----------------> ## 結束做定位操作 ## 切換frame必須成對的出現。 ## 退出切換的frame到默認的網頁html中 driver.switch_to.default_content()
?
?
-
select
select定位有個前提,元素標簽必須是 select
<select> </select>
## 部門是個 select 元素 <select></select> ## 需要3步驟: ## 1. 找到 select 的元素,賦值給變量 dept_select ## 2. 實例化 dept_select 為 Select()的對象 為 user_adding_dept ## 3. 調用 user_adding_dept 的方法 select_by_index()給元素賦值
示例代碼
# 找到 select 的元素,賦值給變量 dept_select dept_select = driver.find_element_by_id("dept") # 實例化 dept_select 為 Select()的對象 為 user_adding_dept user_adding_dept = Select(dept_select) # 調用 user_adding_dept 的方法 select_by_index()給元素賦值 user_adding_dept.select_by_index(2)
-
清除 cookie
在打開瀏覽器的時候,需要清理cookie。
from selenium import webdriver driver = webdriver.Firefox() driver.delete_all_cookies() driver.get("...")
?
-
數據驅動的方式編寫用例
主要有兩種形式進行數據驅動
數據驅動:用外部數據來驅動測試用例的執行
-
數據庫驅動:MySQL、Oracle、PostgreSQL、SQL Server
import pymysql connect = pymysql.connect(host="xx", port=3306, user="root", passwd="xxx", db="xx") cur = connect.cursor() cur.execute("SELECT...") mysql_data = cur.fetchall() for row in mysql_data: # 進行測試 # 使用字典類型 data_to_test = { "key1": row[0], "key2": row[1] } cur.close() connect.close()
?
-
數據文件驅動:csv文件最典型、xml文件、txt文件
import csv csv_file = open("xxx.csv", "r", encoding="utf8") csv_data = csv.reader(csv_file) for row in csv_data: # 進行測試 # 使用字典類型 data_to_test = { "key1": row[0], "key2": row[1] } csv_file.close()
?
-
需要掌握的知識點:
- python的字典類型
dict
類型 - python的讀寫文件
- python的讀寫數據庫
- for循環
- 注意資源的釋放
- 關閉數據庫游標和連接
- 關閉文件
?
- python的字典類型
模塊化的方式編寫用例
需要將每個用例都需要用的公共的功能,抽取出來,放到一個公共類中,作為模塊化
-
創建一個Python Package "common",在里面創建一個ranzhi_common.py文件,里面添加RanzhiCommon類
- login() : 普通登錄,默認用admin/123456登錄
- logout():退出系統
- login_by_dict(user_to_login):使用字典類型的參數進行登錄,user_to_login 是一個字典類型 dict
- change_language(lang):zh_CN, en_US, zh_TW 切換語言,需要參數傳遞要切換的語言
- select_app(app):crm, admin, oa, cash, team 選擇App,需要傳遞選擇 后臺管理 | 客戶管理 。。。
- select_menu_for_admin(menu): organization 選擇了后臺管理以后,選擇菜單 組織
- add_user(user_to_add): 使用字典類型的參數進行添加
-
創建測試用例的類,比如
ranzhi_test_01.py
ranzhi_test_02.py
ranzhi_test_03.py
... 在這些類中調用上面創建的類,一般會放到setUp() 中import unittest from common.ranzhi_common import RanzhiCommon class RanzhiTest01(unittest.TestCase): def setUp(self): ranzhi_common = RanzhiCommon() def test_xxx(self): ranzhi_common.login() ##....
?
Selenium 自動化測試方案
基礎方案
- 使用
unittest
,主要是用TestCase
(測試用例) - 使用模塊化(基本的模塊化,抽取公共模塊)
- 使用數據驅動的方式(主要包括 數據庫的形式 和文件讀取 )
- 定制執行需要測試的用例,使用
unittest
,主要用的是TestSuite
(測試套件)、和TextTestRunner
(文本測試運行器)[或者HTMLTestRunner
] - 生成測試報告(發送報告到指定郵箱)
方案實現的具體步驟:
使用
PyCharm
創建新的PurePython
項目-
在項目中創建如下的文件夾(python package)
- TestCase
- Data
- Common
- TestRunner
- Report
-
分別實現上述模塊
-
在Data中存放數據,CSV文件,或者也可以放到數據中,使用數據驅動
## 使用csv文件 csv.reader() ## 使用數據庫(MySQL),可以參考www.imooc.com的python操作MySQL的視頻 cur.fetchall()
?
-
在Common中,創建測試公共模塊,實現模塊化的操作
## __init__(self, driver: webdriver.Firefox, base_url) self.common = RanzhiCommon(self.driver, self.base_url)
?
-
在TestCase創建自動化測試用例,注意使用
unittest.TestCase
def setUp() def tearDown() det test_xxx()
?
-
在TestRunner創建測試執行器和測試套件,使用
unittest.TestSuite
和HTMLTestRunner(第三方)
test_suite = unittest.TestSuite() test_suite.addTest(RanzhiLogonTc01("test_xxx")) html_test_runner = HTMLTestRunner(stream=report_file, title="xxx", description="dddd") html_test_runner.run(test_suite)
?
在項目根目錄創建
main.py
,作為測試項目的主入口,運行測試。
-
檢查測試報告
Selenium 可能遇到的問題
有無問題?
a <iframe>
f1 = find_element_by_css_selector(frame)
switch_to.frame(f1)
b <select>
s1 = find_element_by_css_selector(select)
ss1 = Select(s1)
ss1.select_by_index(0)
ss1.select_by_value("人事部")
c 編碼問題 utf-8
d 時間等待問題 sleep(5)
單元測試框架
unittest
解決了什么問題?
unittest.TestCase
前置條件
清理
測試過程步驟
斷言 assertEqual(期望值, 實際結果, 錯誤提示)
運行測試 test_開頭的方法
unittest.TestSuite
addTest(xxx("test_batch_login"))
自定義的添加測試用例,并執行
unittest.TextTestRunner
run(suite)
執行創建并維護好的測試套件
test_runner test_suite test_case
測試運行器 測試套件 測試用例
模塊化操作
面向對象的實踐:
1. 編寫一個類,類里面描述公共的方法
2. 實例化這個類,調用這個類的方法
有無問題?
類的構造方法,需要傳遞 webdriver.Firefox()
self.common = RanzhiCommon(self.browser, self.base_url)
數據驅動測試
讀取csv,循環每一行數據進行操作
讀取MySQL,用例存到MySQL中
1. 中文編碼的問題。
# coding="utf-8"
讀csv的時候,添加 encoding='utf-8'
csv.reader(open("xxx.csv", "r", -1, encoding="utf-8")
2. 循環放到最外層
3. 文件路徑在控制臺讀取不到的問題,需要用絕對路徑來指向文件
封裝WebDriver
- 避免第三方代碼的威脅,防止大批量修改測試用例
- 節約人力的成本(如果封裝以后,不需要每個自動化測試工程師都會WebDriver)
- 標準化自動化用例的操作,只需要調用公共的標準模塊就好。