pytest--fixture


前戲

fixture是在測試函數運行前后,由pytest執行的外殼函數。fixture中的代碼可以定制,滿足多變的測試需求,包括定義傳入測試中的數據集、配置測試前系統的初始狀態、為批量測試提供數據源等等。

下面是一個簡單的fixture

import pytest


@pytest.fixture()
def some_data():
    return 37


def test_some_data(some_data):
    assert some_data == 37

我們來運行一下

@pytest.fixture()裝飾器用於聲明函數是一個fixture,如果測試函數的參數列表中包含fixture名,那么pytest會檢測到,並在測試函數運行之前執行該fixture。fixture可以完成任務,也可以返回數據給測試函數。

測試用例test_some_data()的參數列表中包含一個fixture名some_data,pytest會以該名稱搜索fixture。pytest會優先搜索該測試所在的模塊,然后搜索conftest.py

建議:被fixture裝飾的函數別以test命名,比如上面的命名為some_data,而不是test_data。當然,這樣命名也沒有錯,只是為了方便區分是fixture還是測試用例(函數)

conftest.py

fixture可以放在單獨的測試文件里,如果你希望多個測試文件共享fixture,可以在某個公共目錄下新建一個conftest.py文件,將fixture放在其中。

如果你希望fixture的作用域僅限於某個測試文件,那么將它寫在該測試文件里。可以供所在目錄及其子目錄下的測試使用。

說明:

盡管conftest.py是python模塊,但它不能被當測試文件導入,import conftest的用法是不允許出現的。

我們將上面的代碼更改

conftest.py

import pytest


@pytest.fixture()
def some_data():
    return 37

test_fixture.py

def test_some_data(some_data):
    assert some_data == 37

當pytest執行test_some_data函數時,會自動去conftest.py里找some_data並執行,這樣比如我們的用例,有些需要登錄,有些不需要登錄,我們可以給需要登錄的用例加上fixture,當然,fixture也可以自定義使用范圍,是函數,還是類,或者一個模塊,后面會介紹。

fixture配置及銷毀yield

 fixture會在測試函數之前運行,但如果fixture函數包含yield,那么系統會在yield處停止,轉而執行測試函數,等測試函數執行完畢后再回到fixture,繼續執行yield后面的代碼。因此,可以將yield之前的代碼視為配置(setup)過程,將yield之后的代碼視為清理(teardown)過程,無論測試過程中發生了什么,yield之后的代碼都會被執行。

將上面的conftest.py里的代碼修改一下

import pytest


@pytest.fixture()
def some_data():
    yield 37
    print('測試結束')

--setup-show

上面的測試,我們不會看到fixture的執行過程。如果希望看到測試過程中執行的是什么,以及執行的先后順序,pytest提供的--setup-show選項可以實現這個功能

我們的測試被夾在中間,pytest將每一個fixture的執行分成SETUP和TEARDOWN兩部分。

fixture名稱前面的F代表的是fixture的作用范圍,F代表函數級別的作用范圍,如果是S,則代表的是會話級別的作用范圍。

指定fixture作用范圍

 fixture包含一個叫scope(作用范圍)的可選參數,用於控制fixture執行配置和銷毀邏輯的頻率。@pytest.fixture()的scope參數有四個帶選值:function,class,module,session(默認值為function)。前面用到的fixture都沒有指定scope,因此他們的作用范圍都是默認的函數級別。

scope=“function”

函數級別的fixture每個測試函數只需要運行一次,配置代碼在測試用例運行之前運行,銷毀代碼在測試用例運行之后運行。function是scope參數的默認值

 conftest.py

import pytest


@pytest.fixture(scope="function")  # 函數級別的 def login():
    print('登錄成功')

 

test_fixture.py

def test_index(login):
    print('訪問index')


def test_home(login):
    print('訪問home')

執行結果可以看到,我們在執行每個函數之前都執行了fixture

scope=“class”

類級別的fixture每個測試類只需要運行一次,無論測試類里有多少類方法都可以共享這個fixture

conftest.py

import pytest


@pytest.fixture(scope="class")  # 類級別 def login():
    print('登錄成功')

test_fixture.py

class Test1():
    def test_index(self,login):
        print('訪問index1')

    def test_home(self,login):
        print('訪問home1')

class Test2():
    def test_index(self,login):
        print('訪問index2')

    def test_home(self,login):
        print('訪問home2')

 

scope=“module”

 模塊級別的fixture,每個模塊只需要運行一次,無論模塊里有多少個測試函數、類方法或者其他fixture都可以共享這個fixture

只需要修改conftest.py

import pytest


@pytest.fixture(scope="module")  # 模塊級別 def login():
    print('登錄成功')

 

scope=“session”

會話級別的fixture,每次會話只需要運行一次,所有測試函數、方法都可以共享這個fixture

 我們把上面的test_fixture.py在復制一份,改名為test_fixture2,這樣我們在testpytest下就有兩個test文件了

 

如果有兩個文件,把session改為module,則會執行兩次,因為有兩個py文件

 使用usefixtures指定fixture

目前為止用到fixture的測試,都是在測試函數的參數列表中指定fixture,實際上,也可以用@pytest.mark.usefixtures('fixture1', 'fixture2')標記測試函數或類。使用usefixtures,需要在參數列表中指定一個或多個fixture字符串。

使用usefixture和在測試方法中添加fixture參數,二者本體上是差不多的,區別之一在與后者才能使用fixture的返回值

import pytest


@pytest.fixture(scope="function")
def login():
    print('登錄成功')
conftest.py
import pytest


@pytest.mark.usefixtures('login')
def test_index():
    print('訪問index1')


def test_home():
    print('訪問home1')
test_fixture2.py

如果是類值需要在類名上面加上fixture

import pytest


@pytest.mark.usefixtures('login')
class Test1():
    def test_index(self):
        print('訪問index1')

    def test_home(self):
        print('訪問home1')


@pytest.mark.usefixtures('login')
class Test2():
    def test_index(self):
        print('訪問index2')

    def test_home(self):
        print('訪問home2')
類的fixture
@pytest.mark.usefixtures("cleandir", "anotherfixture")指定多個fixture

autouse

不想源測試數據有任何改動,或全部都實現自動應用, 沒特例,也都不需要返回值時可以選擇自動應用

使用fixture中參數autouse=True實現

import pytest


@pytest.fixture(autouse=True)
def login():
    print('登錄成功')
conftest.py
class Test1():
    def test_index(self):
        print('訪問index1')

    def test_home(self):
        print('訪問home1')


class Test2():
    def test_index(self):
        print('訪問index2')

    def test_home(self):
        print('訪問home2')
test_fixture.py
def test_index():
    print('訪問index1')


def test_home():
    print('訪問home1')
test_fixture2.py

可以看到,我們加了autouse=True之后,會給所有的方法都應用,不用再每個方法都使用fixture

 如果級別是class的話,則有class的只會執行一次

為fixture重命名

 fixture的名字展示在使用它的測試或其他fixture函數的參數列表上,通常會和fixture函數名保持一致,但pytest允許使用@pytest.fixture()的name參數對fixture重命名

conftest.py

import pytest


@pytest.fixture(name='login')  # 重命名為login
def alibaba_taobao_app_login():
    print('登錄成功')

test_fixture2.py

def test_index(login):
    print('訪問index1')


def test_home(login):
    print('訪問home1')

這個fixture原來的名字是 alibaba_taobao_app_login ,重命名后變成了login

 查看fixture

 我們可以使用--fixtures命令行選項,並提供所在測試文件名。pytest將列舉所有可供測試使用的fixture,包括重命名的。我們自己重新定義的會出現在底部

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM