【記錄自己的實現過程,和結果無關】
初始實現:
# coding:utf-8
"""
author:@zhouxuan
file:conftest.py
"""
from selenium import webdriver
import pytest
from selenium.webdriver.support.wait import WebDriverWait
import time
from selenium.webdriver.remote.webdriver import By
@pytest.fixture(scope='function')
def login_baidu(request):
dr = webdriver.Chrome()
dr.get('http://www.baidu.com')
dr.maximize_window()
time.sleep(4)
WebDriverWait(dr, 2).until(lambda x: x.find_element_by_xpath('//*[@id="u1"]/a[7]').is_displayed())
dr.find_element(By.XPATH,'//*[@id="u1"]/a[7]').click()
"判斷默認展示的是掃碼登錄還是用戶名登錄"
try:
WebDriverWait(dr, 2).until(lambda x: x.find_element_by_xpath('//p[@title="用戶名登錄"][not(@style)]').is_displayed())
b=1
except:
b=2 #默認登錄方式未掃碼
if b==1:
dr.find_element("xpath",'//p[@title="用戶名登錄"]').click()
dr.find_element(By.NAME,"userName").send_keys('******')
dr.find_element(By.NAME,"password").send_keys('*****')
dr.find_element(By.ID,"TANGRAM__PSP_10__submit").click()
time.sleep(20) #手工識別
print('one')
yield dr
dr.quit()
# def quit():
# print ('run')
# dr.quit()
# request.addfinalizer(quit)
用例腳本test_baidu.py
# coding:utf-8
"""
author:@
"""
import pytest
from selenium.webdriver.remote.webdriver import By
from selenium.webdriver.common.keys import Keys
from test_finance import pri_packaging
import time
class Test_baidu():
def test_search(self,login_baidu):
"""
:param login_baidu: 搜索
:return:
"""
dr=login_baidu
dr.find_element(By.ID,"kw").send_keys('aaa',Keys.ENTER)
def test_setting(self,login_baidu):
"""
:param login_baidu: 搜索設置
:return:
"""
dr=login_baidu
dr.find_element(By.XPATH,'//*[@id="s_usersetting_top"]/span').click() #點擊設置
dr.find_element(By.XPATH,'//*[@id="wrapper"]/div[5]/a[1]').click() #搜索設置
pri_packaging.wait_element_appear(dr,value='//*[@id="s1_2"]')
dr.find_element(By.XPATH,'//*[@id="s1_2"]').click() #搜索框提示不顯示
time.sleep(5)
if __name__ == '__main__':
pytest.main(['-s','test_baidu.py'])
可以看出新增了py文件pri_packaging,我是用來封裝一些常用的方法,這樣寫起來更加簡單
# coding:utf-8
"""
author:zhouxuan
2019/12/30 10:57
PyCharm 封裝常用的方法
"""
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.remote.webdriver import By
def wait_element_appear(driver,timeout=10,by=By.XPATH,value=None):
WebDriverWait(driver, timeout, 1,).until(lambda x: x.find_element(by,value).is_displayed())
執行完畢
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.0.0, py-1.5.4, pluggy-0.13.1
rootdir: D:\django_project\p3_tongtool, inifile: pytest.ini
plugins: allure-pytest-2.8.6, html-2.0.1, metadata-1.8.0, rerunfailures-8.0
collected 2 items
test_baidu.py one
.one
.
========================== 2 passed in 73.88 seconds ==========================
可以看出,用例腳本的可讀性還是偏差,接下來我們就準備把用例腳本寫成類似僞代碼,增加可讀性
優化思路:
1、增加腳本可讀性(爲公司維護腳本人員和新手考慮)
2、腳本相關數據和業務分離
3、常用的方法抽離出來,做成公共函數,方便重複調用。
開始重構上面的用例。在頂級目錄下面創建文件夾conf config.ini用於存儲數據 config.py 系統變量
conf
--config.ini
--config.py
config.ini
[test_baidu]
${var1}=//*[@id="s1_2"]
搜索關鍵字=aaa
設置=//*[@id="s_usersetting_top"]/span
搜索設置=//*[@id="wrapper"]/div[5]/a[1]
加載搜索框tab=${var1}
搜索框提示設置不顯示=${var1}
config.py
import os
ROOT_DIR=os.path.dirname(os.path.dirname(__file__))
# ui對象庫config.ini文件所在目錄
CONF_PATH = os.path.join(ROOT_DIR, 'conf', 'config.ini')
接下來要解析config.ini,我這裏存儲的時候,主要是用按鍵的名稱=識別路徑來存儲的。 結合腳本中的格式是
find_element(By.XPATH,“//*[@id="s_usersetting_top"]/span”).click(),這樣,前面的中文就可以是我們的僞代碼了,顯示在用例中,方便閱讀。最後的替換爲 click_obj(driver,baidu_config.split_content('設置')) 。具體的轉換過程是
1、先封裝find_element_by_xpath(“//*[@id="s_usersetting_top"]/span”).click(),
def click_obj(driver,k_list):
by,value=k_list
paraser_by(by)
driver.find_element(eval(by),value).click()
def paraser_by(by):
if by == 'By.XPATH':
by = By.XPATH
elif by == 'By.ID':
by = By.ID
elif by == 'By.NAME':
by = By.NAME
return by
從上面來看,我們就只需要給出一個list 裏面包含[By.XPATH,//*[@id="s_usersetting_top"]/span].參考個人的風格,我喜歡用xpath來定位元素,所以默認就直接用了xpath,如果是其他的,就在ini文件中搜索設置=By.ID>>//*[@id="wrapper"]/div[5]/a[1]這樣寫,通過解析,來識別出來。具體對應的腳本
from configobj import ConfigObj
from conf.config import CONF_PATH
class parseConfig():
def __init__(self,section):
self.file=CONF_PATH
self.section= section
self.configfile=ConfigObj(self.file,encoding='utf-8')
def get_all_sections(self):
#獲取所有的section
return self.configfile.sections
def get_all_options(self):
#獲取指定的section內容
return self.configfile[self.section]
def split_content(self,option):
#拆解對應的數據
section = self.section
try:
xpath_result = self.configfile[section][option]
if '$' in xpath_result:
xpath_result=self.configfile[section][xpath_result] #對變量${name}解析,替換成真正的值
if '>>' in xpath_result:
return xpath_result.split('>>')
else:
return ['By.XPATH',xpath_result] #默認xpath格式
except Exception as e:
print ('error',e)
其中的split_content就是用來實現上述功能的。這樣返回的就是我們需要的XPATH,以及對象元素的xpath了。
最後腳本就變成了
def test_setting(self,login_baidu):
"""
:param login_baidu: 搜索設置
:return:
"""
baidu_config=parseConfig('test_baidu') #實例化解析類
driver=login_baidu
click_obj(driver,baidu_config.split_content('設置'))
click_obj(driver,baidu_config.split_content('搜索設置'))
waiting_obj(driver,baidu_config.split_content('加載搜索框tab'))
click_obj(driver, baidu_config.split_content('搜索框提示設置不顯示'))
這樣,我們從每個名稱就知道具體的操作步驟了,點擊設置-點擊搜索設置-等待加載tab-設置搜索框不顯示。
最後就說道維護。只要業務流程沒有變,測試腳本就不需要來修改了,就只需要維護測試的相關數據就可以了。這裏就是只需要維護ini文件即可。後續,我們將講述到一個腳本,對應多組測試數據時候,如果來做參數化和維護的
最後的腳本其實還可以做下優化,把解析ini的放到公共函數(click_obj,write_obj)中去,這樣可讀性會更加好。下一偏將給出實際案例。