一、投標用例設計?
# 定義讓前臺頁面保持自動登錄的fixture
@pytest.fixture()
def user_driver():driver = webdriver.Chrome()driver.get("http://47.107.116.139/fangwei/")driver.maximize_window()# 創建頁面類對象page = ReceptionLoginPage(driver)# 通過頁面類對象調用方法執行腳本msg = page.login("admin", "msjy123")# 斷言實際結果print(msg)assert msg == "成功登錄"return driver
- 如何繞過登錄執行投標用例流程,包括投標的正例和反例
- 在瀏覽器的驅動第一次執行前臺頁面登錄之后,保持登錄狀態,在第二次及以上的用例執行投標
定義一個 fixture
- 完成第一次登錄之后進行清除頁面緩存
@pytest.fixture()
# 清除緩存的夾具,可以結合第一次登錄成功之后的夾具一起結合使用
def clear_deal_page(user_driver):user_driver.get("http://47.107.116.139/fangwei/index.php?ctl=deal&id=25070")
- 在投標用例中使用清除緩存的 fixture
出現的問題:可以正常流程去登錄,但是定位點擊馬上投標的元素超時
- 元素找不到
- 問題出現原因:登錄成功之后,界面沒有立馬出現馬上投標元素
def test_user_deal_ok(user_driver, clear_deal_page):# 投標用例執行page = ReceptionLoginPage(user_driver)msg = page.pay("msjy123")print(msg)assert msg == "投標成功!"def test_user_deal_ok2(user_driver, clear_deal_page):# 投標用例執行page = ReceptionLoginPage(user_driver)msg = page.pay("msjy123")print(msg)assert msg == "投標成功!"def test_user_deal_fail(user_driver, clear_deal_page):# 投標用例執行page = ReceptionLoginPage(user_driver)msg = page.pay("msjy1234")print(msg)assert msg == "支付密碼錯誤"
?
- 由于直接進入投標界面可以實現流程用例執行
- 解決方案:
由于登錄成功之后自動跳轉立即投資界面
所以注釋點擊馬上投標的元素
保持登錄的夾具: user_driver 作用域改成 session 級別,保持整個頁面的自動登錄狀態
最終結果:
- 實現投標用例在第一次登錄成功之后,不需要繼續進行登錄,直接執行投標流程用例即可
- 作用:保持第一次之后的登錄狀態來完成投標流程用例執行
# 定義用例腳本執行投標步驟:
def pay(self, password):# - 點擊馬上投標按鈕# self.find_element(*self.btn_deal_submit).click()# - 點擊立即投資self.find_element(*self.btn_money).click()# - 輸入支付密碼self.find_element(*self.ipt_pay_password).send_keys(password)# - 點擊確定按鈕self.find_element(*self.btn_pay_submit).click()# 獲取提示信息的實際結果斷言預期結果msg = self.find_element(*self.pay_msg, need_wait=True).text# - 關閉提示信息彈框self.find_element(*self.txt_deal_msg).click()# 返回用例執行結果msgreturn msg
1. Fixture 作用域控制(scope="session"
)
如果?user_driver
?Fixture 定義時指定了?scope="session"
(需補充代碼確認,但從場景推斷是關鍵),它會在整個測試會話期間只執行一次:
@pytest.fixture(scope="session") # 關鍵:作用域為 session,全局共享
def user_driver():driver = webdriver.Chrome()# 登錄邏輯...return driver
scope="session"
?意味著:整個測試運行中,user_driver
?只會初始化一次瀏覽器、執行一次登錄,所有依賴它的用例共享同一個瀏覽器實例,不會重復打開新窗口。
2. 保持登錄狀態(Cookie/Session 復用)
Web 登錄本質是通過?Cookie 或 Session?維持狀態:
- 首次用例執行時,
user_driver
?完成登錄,瀏覽器會緩存登錄態 Cookie。 - 后續用例復用同一個?
driver
?實例時,瀏覽器自帶已登錄的 Cookie,訪問系統時會自動識別登錄狀態,無需重復登錄。
3. 用例依賴共享實例
測試用例通過參數注入?user_driver
,所有用例拿到的是同一個瀏覽器對象:
def test_bid_2(user_driver, clear_deal_page):# 復用已登錄的 user_driver,無需重新打開窗口/登錄page = ReceptionLoginPage(user_driver) page.pay(...)
因為瀏覽器實例沒銷毀,登錄狀態、頁面上下文都被保留,自然 “跳過登錄、不新開窗口”。
關鍵總結
- Fixture 作用域(
session
)?讓瀏覽器實例全局復用,避免重復初始化。 - Cookie 持久化?讓登錄狀態在同瀏覽器實例內自動延續。
- 最終實現 “一次登錄、多例復用”,跳過重復登錄和窗口打開流程。
?
在自動化測試流程里,user_driver
?結合?clear_deal_page
?主要是為了?解決 “登錄后頁面狀態殘留” 導致的用例干擾問題
1. 「頁面緩存 / 殘留狀態」的干擾問題
登錄后執行投標用例時,頁面可能殘留上一次操作的狀態(比如彈窗未關閉、按鈕狀態異常、緩存數據未清空):
- 示例:第一次投標后,頁面可能停留在 “支付成功” 提示頁,或某些按鈕因狀態變更無法點擊。
- 影響:后續用例執行時,元素定位會失敗(如提示彈窗遮擋按鈕),或流程因殘留狀態報錯,導致測試不穩定。
2.?clear_deal_page
?的核心作用
clear_deal_page
?本質是 **“重置頁面環境” 的 Fixture**,通常做這些事:
@pytest.fixture()
def clear_deal_page(user_driver):# 1. 跳轉到統一的“投標初始化頁面”user_driver.get("http://.../deal?reset=1") # 2. 可能包含清理彈窗、重置按鈕狀態等操作user_driver.execute_script("window.localStorage.clear();") # 清理本地緩存return user_driver
- 重置頁面上下文:強制跳轉到一個 “干凈” 的投標初始頁,確保每次用例執行前,頁面狀態一致(沒有殘留彈窗、按鈕可點擊)。
- 清理緩存 / 狀態:通過 JS 清理?
localStorage
、sessionStorage
,或關閉殘留提示框,避免上一次用例的緩存數據干擾當前用例。
3. 結合?user_driver
?的必要性
user_driver
?負責維持登錄態(共享瀏覽器實例、保留 Cookie),但無法解決 “頁面級的殘留狀態”:
- 只靠?
user_driver
:登錄態是保留了,但頁面可能因上一次用例操作變得 “不干凈”(比如彈窗未關),導致后續用例定位元素超時 / 失敗。 - 結合?
clear_deal_page
:在保留登錄態的基礎上,強制重置頁面環境,讓每個用例都在 “登錄且頁面干凈” 的狀態下執行,既復用了登錄(提升效率),又避免了頁面殘留的干擾(保證穩定)。
二、fixture集中管理?
fixture 的使用形式
- 用例可以直接調用
- fixture 夾具之間可以進行關聯使用
- fixture 夾具可以完成任意測試用例腳本的前后置編寫
- 一般情況下不同的用例使用自定義的 fixture 進行使用
為了降低用例腳本和 fixture 夾具的耦合性,將 fixture 進行集中管理
fixture 一般統一管理放置項目中固定 conftest.py 文件中
?
fixture 定位順序:
- 先從當前運行的 py 文件開始定位 fixture
- 其次從同級目錄的 py 文件中定位 fixture
- 再從項目包的目錄中開始定位定位 fixture
- 然后從 conftest.py 文件中開始定位 fixture
- 最后會從項目所有根目錄定位 fixture
- 以上查找定位 fixture 如果沒有對應的夾具,那么程序會報錯
三、項目重構
對框架代碼進行規劃和分類
在項目重構的過程中,之前導入的路徑使用的模塊,會隨著目錄結構發生變化而變化,不需要手動修改導包路徑
- testcases
- 封裝完成的用例腳本集中管理
- commons
- 項目公共模塊集中使用包
- script
- 用例的線性腳本
- data
- 數據文件相關內容
- log
- 日志信息相關內容
- report
- 缺陷報告記錄的內容
- conftest.py
- 存放 fixture 夾具的集中管理
?
?
四、統一管理項目驅動
目的:為了方便后期做兼容性測試,使用不同的瀏覽器來設計驅動獲取
from selenium.webdriver import Chrome, Firefox, Ie, Edge, Safari
自定義函數獲取對應的瀏覽器驅動
def get_webdriver(name: str = "chrome"):# 根據調用獲取瀏覽器的實參來返回對應的驅動# 將具體瀏覽器實參名字進行整理# 將所有瀏覽器的名字轉化為小寫# 將所有瀏覽器的名字中空格去除# 再返回驅動的驅動name = name.lower()name = name.replace(" ", "")# print(name)# 第一種格式:# if name == "chrome":# return Chrome()# elif name == "firefox":# return Firefox()# 使用match和case關鍵字匹配驅動match name:case "chrome":return Chrome()case "firefox":return Firefox()case "ie":return Ie()case "edge":return Edge()
# get_webdriver("C hrome")
# get_webdriver("C H ro ME")
自定義獲取驅動方式重寫之后
- 需要再創建驅動的地方,調用自定義的
get_webdriver ("對應瀏覽器的名字")
五、后臺登錄的驅動
# 后臺登錄頁面的驅動
@pytest.fixture(scope="session")
def admin_driver():driver = get_webdriver()driver.get("http://47.107.116.139/fangwei/m.php?m=Public&a=login&")# 使用cookie信息load_cookies(driver)# 如果第一次登錄:沒有cookie信息那么正常流程登錄if is_login(driver):# 驗證碼處理code = save_code_img(driver)# 完成正常登錄流程:使用 POM 封裝調用腳本執行page = BackgroundLoginPage(driver)page.login("admin", "msjy123", code)yield driver# 第一次正常登錄之后,用例執行結束之后,完成后置保持 cookie 信息save_cookies(driver)
1. 裝飾器與 fixture 作用域
@pytest.fixture(scope="session")
scope="session"
:表示該 fixture 的作用域是整個測試會話(session)。也就是說,在一次?pytest
?測試運行過程中,這個?admin_driver
?夾具只會被初始化一次,然后在所有需要它的測試用例中復用,測試會話結束時才會執行其后置清理邏輯(yield
?之后的代碼)。這樣可以提升測試效率,比如這里用于保持后臺登錄狀態,避免重復登錄操作。
?
2. 驅動初始化與頁面訪問
driver = get_webdriver()
driver.get("http://47.107.116.139/fangwei/m.php?m=Public&a=login&")
get_webdriver()
:調用了一個自定義的函數(這個函數用于根據配置獲取對應的瀏覽器驅動實例,比如 Chrome、Firefox 等瀏覽器的驅動,方便進行兼容性測試 ),獲取到瀏覽器驅動對象?driver
,后續用這個驅動來操作瀏覽器。driver.get(...)
:使用獲取到的瀏覽器驅動,打開指定的后臺登錄頁面 URL,讓瀏覽器跳轉到對應的登錄界面,為后續登錄操作做準備。
?
3. Cookie 相關操作
# 使用 cookie 信息
load_cookies(driver)
load_cookies(driver)
:調用自定義函數?load_cookies
,作用是嘗試從某個地方加載之前保存的 Cookie 信息,并將其注入到當前的瀏覽器驅動?driver
?中。這樣做的目的是,如果之前有成功登錄過并保存了 Cookie,那么通過加載這些 Cookie,可以直接保持登錄狀態,無需再次輸入賬號密碼等進行登錄,提升測試執行效率。
?
4. 登錄流程處理(條件判斷)
# 如果第一次登錄:沒有 cookie 信息那么正常流程登錄
if is_login(driver):# 驗證碼處理code = save_code_img(driver)# 完成正常登錄流程:使用 POM 封裝調用腳本執行page = BackgroundLoginPage(driver)page.login("admin", "msjy123", code)
is_login(driver)
:調用自定義函數?is_login
,用于判斷當前瀏覽器驅動?driver
?對應的頁面是否處于已登錄狀態。可能的實現邏輯比如檢查頁面中是否存在登錄后的特定元素(如用戶名顯示、登錄狀態標識等 ),或者根據 Cookie 信息判斷會話是否有效。如果返回?True
,說明需要執行正常的登錄流程(一般是首次登錄或者 Cookie 失效等情況 )。save_code_img(driver)
:調用自定義函數?save_code_img
,用于處理登錄頁面的驗證碼。可能的操作包括截取驗證碼圖片、識別驗證碼內容(如果結合了驗證碼識別技術,比如 OCR 等 ),并返回驗證碼的文本內容?code
,以便后續登錄時使用。BackgroundLoginPage(driver)
:這里使用了頁面對象模型(POM,Page Object Model )的設計模式,創建一個?BackgroundLoginPage
?類的實例?page
,并將瀏覽器驅動?driver
?傳入。POM 模式把頁面的元素定位和操作方法封裝到對應的頁面類中,便于代碼維護和復用。page.login("admin", "msjy123", code)
:調用?BackgroundLoginPage
?類中封裝的?login
?方法,傳入用戶名?admin
、密碼?msjy123
?和前面獲取到的驗證碼?code
,執行實際的登錄操作,模擬用戶在頁面上輸入賬號、密碼、驗證碼并提交登錄的流程。
?
5. fixture 的 yield 關鍵字
yield driver
yield
?是?pytest
?fixture 中用于分隔前置操作和后置操作的關鍵字。yield
?之前的代碼屬于前置準備邏輯,執行到?yield
?時,會暫停當前 fixture 的執行,將?driver
?對象返回給調用它的測試用例使用。當所有依賴該 fixture 的測試用例執行完畢后,會回到這個 fixture,繼續執行?yield
?之后的代碼,也就是后置清理 / 保存操作。
?
6. 后置保存 Cookie 操作
# 第一次正常登錄之后,用例執行結束之后,完成后置保持 cookie 信息
save_cookies(driver)
save_cookies(driver)
:調用自定義函數?save_cookies
,在測試用例執行完畢后,將當前瀏覽器驅動?driver
?中的 Cookie 信息保存起來(比如保存到文件、數據庫等 )。這樣,下次再執行測試時,就可以通過前面的?load_cookies
?函數加載這些 Cookie,實現免登錄或者保持登錄狀態的效果,提升后續測試的效率,也能模擬實際用戶的會話保持場景。
?