Pytest Fixture Notes

關(guān)于pytest fixtures,根據(jù)官方文檔介紹: fixture 用于提供一個(gè)固定的基線,使 Cases 可以在此基礎(chǔ)上可靠地、重復(fù)地執(zhí)行疙驾。對(duì)比 PyUnit 經(jīng)典的setup/teardown形式啥纸,它在以下方面有了明顯的改進(jìn):

  1. fixture擁有一個(gè)明確的名稱喜喂,通過聲明使其能夠在函數(shù)究珊、類、模塊纵苛,甚至整個(gè)測(cè)試會(huì)話中被激活使用剿涮;
  2. fixture以一種模塊化的方式實(shí)現(xiàn),原因在于每一個(gè)fixture的名字都能觸發(fā)一個(gè)fixture函數(shù)攻人,而這個(gè)函數(shù)本身又能調(diào)用其它的fixture取试;
  3. fixture的管理從簡(jiǎn)單的單元測(cè)試擴(kuò)展到復(fù)雜的功能測(cè)試,允許通過配置和組件選項(xiàng)參數(shù)化fixture和測(cè)試用例怀吻,或者跨功能瞬浓、類、模塊蓬坡,甚至整個(gè)測(cè)試會(huì)話復(fù)用fixture猿棉;

一句話概括:在整個(gè)測(cè)試執(zhí)行的上下文中,fixture扮演注入者(injector)的角色屑咳,而測(cè)試用例扮演消費(fèi)者(client)的角色萨赁,測(cè)試用例可以輕松的接收和處理需要預(yù)初始化操作的應(yīng)用對(duì)象,而不用過分關(guān)心其實(shí)現(xiàn)的具體細(xì)節(jié)兆龙。

fixture的實(shí)例化順序

fixture支持的作用域(Scope):function(default)杖爽、class、module紫皇、package慰安、session。
其中聪铺,package作用域是在 pytest 3.7 的版本中化焕,正式引入的,目前仍處于實(shí)驗(yàn)性階段铃剔。
多個(gè)fixture的實(shí)例化順序锣杂,遵循以下原則:

  1. 高級(jí)別作用域的(例如:session)優(yōu)先于 低級(jí)別的作用域的(例如:class或者function)實(shí)例化;
  2. 相同級(jí)別作用域的番宁,其實(shí)例化順序遵循它們?cè)跍y(cè)試用例中被聲明的順序(也就是形參的順序)元莫,或者fixture之間的相互調(diào)用關(guān)系;
  3. 指明autouse=True的fixture蝶押,先于其同級(jí)別的其它fixture實(shí)例化踱蠢。

fixture 實(shí)現(xiàn) teardown 功能

有以下幾種方法:

注意:在yield之前或者addfinalizer注冊(cè)之前代碼發(fā)生錯(cuò)誤退出的,都不會(huì)再執(zhí)行后續(xù)的清理操作。

  1. 將fixture變?yōu)樯善鞣椒ǎㄍ扑])
    即將fixture函數(shù)中的return關(guān)鍵字替換成yield茎截,則yield之后的代碼苇侵,就是我們要的清理操作。
@pytest.fixture(scope='session', autouse=True)
def clear_token():
    yield
    from libs.redis_m import RedisManager
    rdm = RedisManager()
    rdm.expire_token(seconds=60)
  1. 使用addfinalizer方法
    fixture函數(shù)能夠接收一個(gè)request的參數(shù)企锌,表示測(cè)試請(qǐng)求的上下文(下面會(huì)詳細(xì)介紹)榆浓,我們可以使用request.addfinalizer方法為fixture添加清理函數(shù)。
@pytest.fixture()
def smtp_connection_fin(request):
    smtp_connection = smtplib.SMTP("smtp.163.com", 25, timeout=5)

    def fin():
        smtp_connection.close()

    request.addfinalizer(fin)
    return smtp_connection
  1. 使用with寫法(不推薦)
    對(duì)于支持with寫法的對(duì)象撕攒,我們也可以隱式的執(zhí)行它的清理操作:
@pytest.fixture()
def smtp_connection_yield():
    with smtplib.SMTP("smtp.163.com", 25, timeout=5) as smtp_connection:
        yield smtp_connection

fixture可以訪問測(cè)試請(qǐng)求的上下文

fixture函數(shù)可以接收一個(gè)request的參數(shù)陡鹃,表示測(cè)試用例、類抖坪、模塊萍鲸,甚至測(cè)試會(huì)話的上下文環(huán)境;
例如可以擴(kuò)展下上面的smtp_connection_yield擦俐,讓其根據(jù)不同的測(cè)試模塊使用不同的服務(wù)器:

@pytest.fixture(scope='module')
def smtp_connection_request(request):
    server, port = getattr(request.module, 'smtp_server', ("smtp.163.com", 25))
    with smtplib.SMTP(server, port, timeout=5) as smtp_connection:
        yield smtp_connection
        print("斷開 %s:%d" % (server, port))

在測(cè)試模塊中指定smtp_server

smtp_server = ("mail.python.org", 587)
def test_163(smtp_connection_request):
    response, _ = smtp_connection_request.ehlo()
    assert response == 250

fixture返回工廠函數(shù)

如果需要在一個(gè)測(cè)試用例(function)中脊阴,多次使用同一個(gè)fixture實(shí)例,相對(duì)于直接返回?cái)?shù)據(jù)蚯瞧,更好的方法是返回一個(gè)產(chǎn)生數(shù)據(jù)的工廠函數(shù)嘿期。并且,對(duì)于工廠函數(shù)產(chǎn)生的數(shù)據(jù)埋合,也可以在fixture中對(duì)其管理:

@pytest.fixture
def make_customer_record():

    # 記錄生產(chǎn)的數(shù)據(jù)
    created_records = []

    # 工廠
    def _make_customer_record(name):
        record = models.Customer(name=name, orders=[])
        created_records.append(record)
        return record

    yield _make_customer_record

    # 銷毀數(shù)據(jù)
    for record in created_records:
        record.destroy()


def test_customer_records(make_customer_record):
    customer_1 = make_customer_record("Lisa")
    customer_2 = make_customer_record("Mike")
    customer_3 = make_customer_record("Meredith")

fixture的參數(shù)化

如果你需要在一系列的測(cè)試用例的執(zhí)行中秽五,每輪執(zhí)行都使用同一個(gè)fixture,但是有不同的依賴場(chǎng)景饥悴,那么可以考慮對(duì)fixture進(jìn)行參數(shù)化坦喘;這種方式適用于對(duì)多場(chǎng)景的功能模塊進(jìn)行詳盡的測(cè)試。

@pytest.fixture(scope='module', params=['smtp.163.com', "mail.python.org"])
def smtp_connection_params(request):
    server = request.param
    with smtplib.SMTP(server, 587, timeout=5) as smtp_connection:
        yield smtp_connection

def test_parames(smtp_connection_params):
    response, _ = smtp_connection_params.ehlo()
    assert response == 250

在不同的層級(jí)上覆寫fixture

注意:低級(jí)別的作用域可以調(diào)用高級(jí)別的作用域西设,但是高級(jí)別的作用域調(diào)用低級(jí)別的作用域會(huì)返回一個(gè)ScopeMismatch的異常瓣铣。

在大型的測(cè)試中,可能需要在本地覆蓋項(xiàng)目級(jí)別的fixture贷揽,以增加可讀性和便于維護(hù):

@pytest.fixture(scope="module", autouse=True)
def init(frag_login):
    pass

@pytest.fixture(scope='session')
def active_user_account(cmd_line_args, conf):
    tail_num = cmd_line_args.get("tailnum", None)
    if tail_num is None:
        tail_num = "1"
    for user in conf['unified']:
        if str(user['uid'])[-1] == tail_num:
            return user
    msg = f"尾號(hào)[{tail_num}], 在配置文件中未找到"
    logger.error(msg)
    raise ValueError(msg)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棠笑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子禽绪,更是在濱河造成了極大的恐慌蓖救,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件印屁,死亡現(xiàn)場(chǎng)離奇詭異循捺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)雄人,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門从橘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事恰力〔婷眨” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵踩萎,是天一觀的道長(zhǎng)泌辫。 經(jīng)常有香客問我绅络,道長(zhǎng)袱院,這世上最難降的妖魔是什么悼嫉? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮回还,結(jié)果婚禮上裆泳,老公的妹妹穿的比我還像新娘叹洲。我一直安慰自己柠硕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布运提。 她就那樣靜靜地躺著蝗柔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪民泵。 梳的紋絲不亂的頭發(fā)上癣丧,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音栈妆,去河邊找鬼胁编。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鳞尔,可吹牛的內(nèi)容都是我干的嬉橙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼寥假,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼市框!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起糕韧,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤枫振,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后萤彩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粪滤,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年雀扶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了额衙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖窍侧,靈堂內(nèi)的尸體忽然破棺而出县踢,到底是詐尸還是另有隱情,我是刑警寧澤伟件,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布硼啤,位于F島的核電站,受9級(jí)特大地震影響斧账,放射性物質(zhì)發(fā)生泄漏谴返。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一咧织、第九天 我趴在偏房一處隱蔽的房頂上張望嗓袱。 院中可真熱鬧,春花似錦习绢、人聲如沸渠抹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梧却。三九已至,卻和暖如春败去,著一層夾襖步出監(jiān)牢的瞬間放航,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工圆裕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留广鳍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓吓妆,卻偏偏與公主長(zhǎng)得像赊时,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耿战,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353