pytest自動化之腳本實現和優化

【記錄自己的實現過程,和結果無關】

初始實現:

# 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)中去,這樣可讀性會更加好。下一偏將給出實際案例。

發佈了106 篇原創文章 · 獲贊 22 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章