溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python接口自動(dòng)化之正則用例參數(shù)化示例分析

發(fā)布時(shí)間:2022-07-13 10:59:17 來(lái)源:億速云 閱讀:157 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“python接口自動(dòng)化之正則用例參數(shù)化示例分析”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“python接口自動(dòng)化之正則用例參數(shù)化示例分析”吧!

    前言

    我們?cè)谧鼋涌谧詣?dòng)化的時(shí)候,處理接口依賴的相關(guān)數(shù)據(jù)時(shí),通常會(huì)使用正則表達(dá)式來(lái)進(jìn)行提取相關(guān)的數(shù)據(jù)。

    正則表達(dá)式,又稱正規(guī)表示式、正規(guī)表示法、正規(guī)表達(dá)式、規(guī)則表達(dá)式、常規(guī)表示法(Regular Expression,在代碼中常簡(jiǎn)寫為regex、regexp或RE) 。它是一個(gè)特殊的字符序列,它能幫助你方便的檢查一個(gè)字符串是否與某種模式匹配。在很多文本編輯器里,正則表達(dá)式通常被用來(lái)檢索、替換那些匹配某個(gè)模式的文本。而Python 自1.5版本起增加了re模塊,它提供 Perl 風(fēng)格的正則表達(dá)式模式。

    一、正則表達(dá)式語(yǔ)法

    1.1表示單字符

    單字符:即表示一個(gè)單獨(dú)的字符,比如匹配數(shù)字用\d,匹配非數(shù)字用\D。

    除以下語(yǔ)法,也可以匹配指定的具體字符,可以是1個(gè)也可以是多個(gè)。

    字符

    功能說(shuō)明

    .

    匹配任意1個(gè)字符(除了\n)

    [2a]

    匹配[]中括號(hào)中列舉的字符,如這里就是匹配2或者a這兩個(gè)字符其中的一個(gè)

    \d

    匹配數(shù)字,即0-9

    \D

    匹配非數(shù)字

    \s

    匹配空白,即空格、tab鍵(tab鍵為兩個(gè)空格)

    \S

    匹配非空白

    \w

    匹配單詞字符,即a-z、A-Z、0-9、_(數(shù)字、字母、下劃線)

    \W

    匹配非單詞字符

    實(shí)例如下,這里先說(shuō)明一下findall(匹配規(guī)則,要匹配的字符串)這個(gè)方法是查找所有匹配的數(shù)據(jù),以列表的形式返回,后面會(huì)在re模塊進(jìn)行詳解:

    import re
    # .:匹配任意1個(gè)字符
    re1 = r'.'
    res1 = re.findall(re1, '\nj8?0\nbth\nihb')
    print(res1)	# 運(yùn)行結(jié)果:['j', '8', '?', '0', 'b', 't', 'h', 'i', 'h', 'b']
    # []:匹配列舉中的其中一個(gè)
    re2 = r"[abc]"
    res2 = re.findall(re2, '1iugfiSHOIFUOFGIDHFGFD2345a6a78b99cc')
    print(res2)	# 運(yùn)行結(jié)果:['a', 'a', 'b', 'c', 'c']
    # \d:匹配一個(gè)數(shù)字
    re3 = r"\d"
    res3 = re.findall(re3, "dfghjkl32212dfghjk")
    print(res3)	# 運(yùn)行結(jié)果:['3', '2', '2', '1', '2']
    # \D:匹配一個(gè)非數(shù)字
    re4 = r"\D"
    res4 = re.findall(re4, "d212dk?\n$%3;]a")
    print(res4)	# 運(yùn)行結(jié)果:['d', 'd', 'k', '?', '\n', '$', '%', ';', ']', 'a']
    # \s:匹配一個(gè)空白鍵或tab鍵(tab鍵實(shí)際就是兩個(gè)空白鍵)
    re5 = r"\s"
    res5 = re.findall(re5,"a s d a  9999")
    print(res5)	# 運(yùn)行結(jié)果:[' ', ' ', ' ', ' ', ' ']
    # \S: 匹配非空白鍵
    re6 = r"\S"
    res6 = re.findall(re6, "a s d a  9999")
    print(res6)	# 運(yùn)行結(jié)果:['a', 's', 'd', 'a', '9', '9', '9', '9']
    # \w:匹配一個(gè)單詞字符(數(shù)字、字母、下劃線)
    re7 = r"\w"
    res7 = re.findall(re7, "ce12sd@#a as_#$")
    print(res7)	# 運(yùn)行結(jié)果:['c', 'e', '1', '2', 's', 'd', 'a', 'a', 's', '_']
    # \W:匹配一個(gè)非單詞字符(不是數(shù)字、字母、下劃線)
    re8 = r"\W"
    res8 = re.findall(re8, "ce12sd@#a as_#$")
    print(res8)	# 運(yùn)行結(jié)果:['@', '#', ' ', '#', '$']
    # 匹配指定字符
    re9 = r"python"
    res9 = re.findall(re9, "cepy1thon12spython123@@python")
    print(res9)	# 運(yùn)行結(jié)果:['python', 'python']

    1.2表示數(shù)量

    如果要匹配某個(gè)字符多次,就可以在字符后面加上數(shù)量進(jìn)行表示,具體規(guī)則如下:

    字符

    功能說(shuō)明

    *

    匹配前一個(gè)字符出現(xiàn)0次或者無(wú)限次,即可有可無(wú)

    +

    匹配前一個(gè)字符出現(xiàn)1次或無(wú)限次,即至少1次

    ?

    匹配前一個(gè)字符出現(xiàn)0次或1次,即要么沒(méi)有,要么只有1次

    {m}

    匹配前一個(gè)字符出現(xiàn)m次

    {m,}

    匹配前一個(gè)字符至少出現(xiàn)m次

    {m,n}

    匹配前一個(gè)字符出現(xiàn)從m到n次

    實(shí)例如下:

    import re
    # *:表示前一個(gè)字符出現(xiàn)0次以上(包括0次)
    re21 = r"\d*"   # 這里匹配的規(guī)則,前一個(gè)字符是數(shù)字
    res21 = re.findall(re21, "343aa1112df345g1h7699")  # 如匹配到a時(shí),屬于符合0次,但因?yàn)闆](méi)有值所以會(huì)為空
    print(res21)	# 運(yùn)行結(jié)果:['343', '', '', '1112', '', '', '345', '', '1', '', '6699', '']
     
    # ? : 表示0次或者一次
    re22 = r"\d?"
    res22 = re.findall(re22, "3@43*a111")
    print(res22)	# 運(yùn)行結(jié)果:['3', '', '4', '3', '', '', '1', '1', '1', '']
     
    # {m}:表示匹配一個(gè)字符m次
    re23 = r"1[3456789]\d{9}" # 手機(jī)號(hào):第1位為1,第2位匹配列舉的其中1個(gè)數(shù)字,第3位開始是數(shù)字,且匹配9次
    res23 = re.findall(re23,"sas13566778899fgh356912345678jkghj12788990000aaa113588889999")
    print(res23)	# 運(yùn)行結(jié)果:['13566778899', '13588889999']
     
    # {m,}:表示匹配一個(gè)字符至少m次
    re24 = r"\d{7,}"
    res24 = re.findall(re24, "sas12356fgh2234567jkghj12788990000aaa113588889999")
    print(res24)	# 運(yùn)行結(jié)果:['1234567', '12788990000', '113588889999']
     
    # {m,n}:表示匹配一個(gè)字符出現(xiàn)m次到n次
    re25 = r"\d{3,5}"
    res25 = re.findall(re25, "aaaaa123456ghj333yyy77iii88jj909768876")
    print(res25)	# 運(yùn)行結(jié)果:['12345', '333', '90976', '8876']
    1.2.1匹配分組

    字符

    功能說(shuō)明

    |

    匹配左右任意一個(gè)表達(dá)式

    (ab)

    將括號(hào)中字符作為一個(gè)分組

    實(shí)例如下:

    import re
    # 同時(shí)定義多個(gè)規(guī)則,只要滿足其中一個(gè)
    re31 = r"13566778899|13534563456|14788990000"
    res31 = re.findall(re31, "sas13566778899fgh23534563456jkghj14788990000")
    print(res31)	# 運(yùn)行結(jié)果:['13566778899', '13534563456', '14788990000']
    # ():匹配分組:在匹配規(guī)則的數(shù)據(jù)中提取括號(hào)里的數(shù)據(jù)
    re32 = r"aa(\d{3})bb"	# 如何數(shù)據(jù)符合規(guī)則,結(jié)果只會(huì)取括號(hào)中的數(shù)據(jù),即\d{3}
    res32 = re.findall(re32, "ggghjkaa123bbhhaa672bbjhjjaa@45bb")
    print(res32)	# 運(yùn)行結(jié)果:['123', '672']

    1.3 表示邊界

    字符

    功能說(shuō)明

    ^

    匹配字符串開頭,只能匹配開頭

    $

    匹配字符串結(jié)尾,只能匹配結(jié)尾

    \b

    匹配一個(gè)單詞的邊界(單詞:字母、數(shù)字、下劃線)

    \B

    匹配非單詞的邊界

    實(shí)例如下:

    import re
    # ^:匹配字符串的開頭
    re41 = r"^python"   # 字符串開頭為python
    res41 = re.findall(re41, "python999python")  # 只會(huì)匹配這個(gè)字符串的開頭
    res411 = re.findall(re41, "1python999python")  # 因?yàn)殚_頭是1,第1位就不符合了
    print(res41)	# 運(yùn)行結(jié)果:['python']
    print(res411)	# 運(yùn)行結(jié)果:[]
     
    # $:匹配字符串的結(jié)尾
    re42=r"python$"	# 字符串以python結(jié)尾
    res42 = re.findall(re42, "python999python")
    print(res42)	# 運(yùn)行結(jié)果:['python']
     
    # \b:匹配單詞的邊界,單詞即:字母、數(shù)字、下劃線
    re43 = r"\bpython"  # 即匹配python,且python的前一位是不是單詞
    res43 = re.findall(re43, "1python 999 python")  # 這里第1個(gè)python的前1位是單詞,因此第1個(gè)是不符合的
    print(res43)	# 運(yùn)行結(jié)果:['python']
     
    # \B:匹配非單詞的邊界
    re44 = r"\Bpython"  # 即匹配python,且python的前一位是單詞
    res44 = re.findall(re44, "1python999python")
    print(res44)	# 運(yùn)行結(jié)果:['python', 'python']

    二、貪婪模式

    python里數(shù)量詞默認(rèn)是貪婪的,總是嘗試匹配盡可能多的字符,而非貪婪模式則是嘗試匹配盡可能少的字符,在表示數(shù)量的表達(dá)式后加上問(wèn)號(hào)(?)就可以關(guān)閉貪婪模式。

    如下例子,匹配2個(gè)以上的數(shù)字,如果符合條件它會(huì)一直匹配到不符合才停止,如其中的34656fya,34656符合2個(gè)數(shù)字以上,那么它會(huì)一直匹配到6為止,如果關(guān)閉貪婪模式,那么在滿足2個(gè)數(shù)字時(shí)就會(huì)停止,最后可以匹配到34、65。

    import re
    # 默認(rèn)的貪婪模式下
    test = 'aa123aaaa34656fyaa12a123d'
    res = re.findall(r'\d{2,}', test)
    print(res)	# 運(yùn)行結(jié)果:['123', '34656', '12', '123']
     
    # 關(guān)閉貪婪模式
    res2 = re.findall(r'\d{2,}?', test)
    print(res2)	# 運(yùn)行結(jié)果:['12', '34', '65', '12', '12']

    三、re模塊

    在python中使用正則表達(dá)式,就會(huì)用到re模塊來(lái)進(jìn)行操作,提供的方法一般需要傳入兩個(gè)參數(shù):

    • 參數(shù)1: 匹配的規(guī)則

    • 參數(shù)2:要進(jìn)行匹配的字符串

    3.1 re.findall()

    查找所有符合規(guī)范的字符串,以列表的形式返回。

    import re
    test = 'aa123aaaa34656fyaa12a123d'
    res = re.findall(r'\d{2,}', test)
    print(res)	# 運(yùn)行結(jié)果:['123', '34656', '12', '123']

    3.2re.search()

    查找第一個(gè)符合規(guī)范的字符串,返回的是一個(gè)匹配對(duì)象,可以通過(guò)group()將匹配到的數(shù)據(jù)直接提取出來(lái)。

    import re
    s = "123abc123aaa123bbb888ccc"
    res2 = re.search(r'123', s)
    print(res2)  # 運(yùn)行結(jié)果:<re.Match object; span=(0, 3), match='123'>
     
    # 通過(guò)group將匹配到的數(shù)據(jù)提取出來(lái),返回類型為str
    print(res2.group())   # 運(yùn)行結(jié)果:123

    返回的匹配對(duì)象中,span為匹配到的數(shù)據(jù)的下標(biāo)范圍,match則是匹配到的值。

    group()參數(shù)說(shuō)明:

    • 不傳參數(shù):獲取的是匹配到的所有內(nèi)容

    • 傳入數(shù)值:可以通過(guò)參數(shù)來(lái)指定,獲取第幾個(gè)分組中的內(nèi)容(獲取第1個(gè)分組,傳入?yún)?shù)1,獲取第2個(gè)分組,傳入?yún)?shù)2,依次類推。)

    import re
    s = "123abc123aaa123bbb888ccc"
    re4 = r"aaa(\d{3})bbb(\d{3})ccc"	# 這里分組就是前面說(shuō)到的匹配語(yǔ)法:()
    res4 = re.search(re4, s)
    print(res4)
    # group不傳參數(shù):獲取的是匹配到的所有內(nèi)容
    # group通過(guò)參數(shù)指定,獲取第幾個(gè)分組中的內(nèi)容(獲取第1個(gè)分組,傳入?yún)?shù)1,獲取第2個(gè)分組,傳入?yún)?shù)2,依次類推..
    print(res4.group())
    print(res4.group(1))
    print(res4.group(2))

    3.3 re.match()

    從字符串的起始位置進(jìn)行匹配,匹配成功則返回匹配到的對(duì)象,如果開頭的位置不符合匹配的規(guī)則,不會(huì)繼續(xù)往后面去匹配,直接返回None。re.match()與re.search()都是只匹配一個(gè),不一樣的是,前者只匹配字符串的開頭,后者則是會(huì)匹配整個(gè)字符串,但只獲取第一個(gè)符合的數(shù)據(jù)。

    import re
    s = "a123abc123aaa1234bbb888ccc"
    # match:只匹配字符串的開頭,開頭不符合就返回None
    res1 = re.match(r"a123", s)
    res2 = re.match(r"a1234", s)
    print(res1)  # 運(yùn)行結(jié)果:<re.Match object; span=(0, 4), match='a123'>
    print(res2)  # 運(yùn)行結(jié)果:None

    3.4re.sub()

    檢索和替換:用于替換字符串中的匹配項(xiàng)

    re.sub()參數(shù)說(shuō)明:

    • 參數(shù)1:待替換的字符串

    • 參數(shù)2:目標(biāo)字符串

    • 參數(shù)3:要進(jìn)行替換操作的字符串

    • 參數(shù)4:可以指定最多替換的次數(shù),非必填(默認(rèn)替換所有符合規(guī)范的字符串)

    import re
    s = "a123abc123aaa123bbb888ccc"
    # <font color="#FF0000">參數(shù)1:</font>待替換的字符串
    # <font color="#FF0000">參數(shù)2:</font>目標(biāo)字符串
    # <font color="#FF0000">參數(shù)3:</font>要進(jìn)行替換操作的字符串
    # <font color="#FF0000">參數(shù)4:</font>可以指定最多替換的次數(shù),非必填(默認(rèn)替換所有符合規(guī)范的字符串)
    res5 = re.sub(r'123', "666", s, 4)
    print(res5)  # 運(yùn)行結(jié)果:a666abc666aaa666bbb888ccc

    四、用例參數(shù)化

    在接口自動(dòng)化測(cè)試中,我們的測(cè)試數(shù)據(jù)都是保存在excel中的,有些參數(shù)如果寫死一個(gè)數(shù)據(jù),可能換個(gè)場(chǎng)景或者換個(gè)環(huán)境就不能用了,那么切換環(huán)境時(shí)就需要先把新環(huán)境的測(cè)試數(shù)據(jù)準(zhǔn)備好,并且能支持去跑我們的腳本,或者把excel的數(shù)據(jù)修改為適合新環(huán)境的測(cè)試數(shù)據(jù),維護(hù)的成本較高。因此就需要把我們的自動(dòng)化腳本測(cè)試數(shù)據(jù)盡量地參數(shù)化,降低維護(hù)成本。

    我們先看簡(jiǎn)單版的參數(shù)化,以登錄為例,登錄時(shí)用到的賬號(hào)、密碼等信息都可以提取出來(lái)放到配置文件,修改數(shù)據(jù)或更換環(huán)境時(shí)直接在配置文件中統(tǒng)一修改就可以了。

    python接口自動(dòng)化之正則用例參數(shù)化示例分析

    python接口自動(dòng)化之正則用例參數(shù)化示例分析

    但如果有多個(gè)不同的數(shù)據(jù)需要參數(shù)化呢,每個(gè)參數(shù)都加個(gè)判斷去替換數(shù)據(jù)嗎?這樣的代碼既啰嗦又不好維護(hù),這時(shí)re模塊就可以用上了,直接看一個(gè)實(shí)例:

    import re
    from common.myconfig import conf
    class TestData:
        """用于臨時(shí)保存一些要替換的數(shù)據(jù)"""
        pass
    def replace_data(data):
        r = r"#(.+?)#"	# 注意這個(gè)分組()內(nèi)的內(nèi)容
        # 判斷是否有需要替換的數(shù)據(jù)
        while re.search(r, data):
            res = re.search(r, data)	# 匹配出第一個(gè)要替換的數(shù)據(jù)
            item = res.group()	# 提取要替換的數(shù)據(jù)內(nèi)容
            key = res.group(1)	# 獲取要替換內(nèi)容中的數(shù)據(jù)項(xiàng)
            try:
                # 根據(jù)替換內(nèi)容中的數(shù)據(jù)項(xiàng)去配置文件中找到對(duì)應(yīng)的內(nèi)容,進(jìn)行替換
                data = data.replace(item, conf.get_str("test_data", key))
            except:
                # 如果在配置文件中找不到就在臨時(shí)保存的數(shù)據(jù)中找,然后替換
                data = data.replace(item, getattr(TestData, key))
        return data

    注意這里的正則表達(dá)式是有使用?關(guān)閉貪婪模式的,因?yàn)闇y(cè)試數(shù)據(jù)中可能會(huì)需要參數(shù)化2個(gè)或以上的數(shù)據(jù),如果不關(guān)閉貪婪模式,它就只能匹配搭配一個(gè)數(shù)據(jù),舉例如下:

    import re
    data = '{"mobile_phone":"#phone#","pwd":"#pwd#","user":#user#}'
    r1 = "#(.+)#"
    res1 = re.findall(r1, data)
    print(res1)  # 運(yùn)行結(jié)果:['phone#","pwd":"#pwd#","user":#user']	注意這里單引號(hào)只有一個(gè)數(shù)據(jù)
    print(len(res1))      # 運(yùn)行結(jié)果:1
    r2 = "#(.+?)#"
    res2 = re.findall(r2, data)
    print(res2)  # 運(yùn)行結(jié)果:['phone', 'pwd', 'user']
    print(len(res2))      # 運(yùn)行結(jié)果:3

    另外提到的一個(gè)用于臨時(shí)保存數(shù)據(jù)的類,這里主要用于保存接口返回的數(shù)據(jù),因?yàn)橛行y(cè)試數(shù)據(jù)是動(dòng)態(tài)變化的,可能要依賴于某個(gè)接口,后面的測(cè)試用例又需要這些數(shù)據(jù),那么我們?cè)诮涌诜祷貢r(shí)就可以保存到這個(gè)類里作為一個(gè)類屬性,接著在需要用這個(gè)數(shù)據(jù)的測(cè)試用例時(shí),把這個(gè)類屬性提取出來(lái)替換到測(cè)試數(shù)據(jù)中即可。提示:設(shè)置屬性setattr(對(duì)象, 屬性名, 屬性值),獲取屬性值getattr(對(duì)象, 屬性名)。

    到此,相信大家對(duì)“python接口自動(dòng)化之正則用例參數(shù)化示例分析”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI