Python測試框架之pytest高級用法之fixture(三)


前置條件:

1.文件路徑:

Test_App
    - - test_abc.py
    - - pytest.ini

 2.pyetst.ini配置文件內容:

 
[pytest]
  命令行參數
 addopts = -s
 搜索文件名
 python_files = test*.py
  搜索的類名
 python_classes = Test*
搜索的函數名
 python_functions = test_*

  pytest之fixture

fixture修飾器來標記固定的工廠函數,在其他函數,模塊,類或整個工程調用它時會被激活並優先執行,通常會被用於完成預置處理和重復操作。

方法:fixture(scope="function", params=None, autouse=False, ids=None, name=None)
常用參數:
scope:被標記方法的作用域  session>module>class>function
function" (default):作用於每個測試方法,每個test都運行一次
"class":作用於整個類,每個class的所有test只運行一次 一個類中可以有多個方法
"module":作用於整個模塊,每個module的所有test只運行一次;每一個.py文件調用一次,該文件內又有多個function和class
"session:作用於整個session(慎用),每個session只運行一次;是多個文件調用一次,可以跨.py文件調用,每個.py文件就是module
params:(list類型)提供參數數據,供調用標記方法的函數使用;一個可選的參數列表,它將導致多個參數調用fixture功能和所有測試使用它。
autouse:是否自動運行,默認為False不運行,設置為True自動運行;如果True,則為所有測試激活fixture func可以看到它。如果為False則顯示需要參考來激活fixture

ids:每個字符串id的列表,每個字符串對應於params這樣他們就是測試ID的一部分。如果沒有提供ID它們將從params自動生成;是給每一項params參數設置自定義名稱用,意義不大。

 name:fixture的名稱。這默認為裝飾函數的名稱。如果fixture在定義它的統一模塊中使用,夾具的功能名稱將被請求夾具的功能arg遮蔽,解決這個問題的一種方法時將裝飾函數命    令"fixture_<fixturename>"然后使用"@pytest.fixture(name='<fixturename>')"。

  fixture第一個例子(通過參數引用)

class Test_ABC:
    @pytest.fixture()
    def before(self):
        print("------->before")
    def test_a(self,before): # ️ test_a方法傳入了被fixture標識的函數,已變量的形式
        print("------->test_a")
        assert 1
if __name__ == '__main__':
    pytest.main(["-s  test_abc.py"])
         .

  

使用多個fixture

如果用例需要用到多個fixture的返回數據,fixture也可以返回一個元祖,list或字典,然后從里面取出對應數據。

import pytest
@pytest.fixture()
def test1():
    a = 'door'
    b = '123456'
    print('傳出a,b')
    return (a, b)
def test_2(test1):
    u = test1[0]
    p = test1[1]
    assert u == 'door'
    assert p == '123456'
    print('元祖形式正確')
if __name__ == '__main__':
    pytest.main(['-s','test_abc.py'])

  

  當然也可以分成多個fixture,然后在用例中傳多個fixture參數

import pytest
@pytest.fixture()
def test1():
    a = 'door'
    print('\n傳出a')
    return a
@pytest.fixture()
def test2():
    b = '123456'
    print('傳出b')
    return b
def test_3(test1, test2):
    u = test1
    p = test2
    assert u == 'door'
    assert p == '123456'
    print('傳入多個fixture參數正確')
if __name__ == '__main__':
    pytest.main(['-s','test_abc.py'])

  

 

 

 

 

 fixture第二個例子(通過函數引用)

import pytest
@pytest.fixture() # fixture標記的函數可以應用於測試類外部
def before():
    print("------->before")
@pytest.mark.usefixtures("before")#1.需要前面標記了before函數,這才可以用,所以需求before函數前面標記@pytest.fixture();2.前面標記了before函數,這不引用的話,執行后不執行before函數
                     比如在接口測試中有需要先登錄的就可以使用這個用法
class Test_ABC: def setup(self): print("------->setup") def test_a(self): print("------->test_a") assert 1 if __name__ == '__main__': pytest.main(["-s","test_abc.py"])

  

 使用裝飾器@pytest.mark.usefixtures()修飾需要運行的用例

import pytest
@pytest.fixture()
def test1():
    print('\n開始執行function')
@pytest.mark.usefixtures('test1')
def test_a():
    print('---用例a執行---')
@pytest.mark.usefixtures('test1')
class Test_Case:
    def test_b(self):
        print('---用例b執行---')
    def test_c(self):
        print('---用例c執行---')
if __name__ == '__main__':
    pytest.main(['-s', 'test_abc.py'])

  

疊加usefixtures

如果一個方法或者一個class用例想要同時調用多個fixture,可以使用@pytest.mark.usefixture()進行疊加。注意疊加順序,先執行的放底層,后執行的放上層。

import pytest
@pytest.fixture()
def test1():
    print('\n開始執行function1')
@pytest.fixture()
def test2():
    print('\n開始執行function2')
@pytest.mark.usefixtures('test1')
@pytest.mark.usefixtures('test2')
def test_a():
    print('---用例a執行---')
@pytest.mark.usefixtures('test2')
@pytest.mark.usefixtures('test1')
class Test_Case:
    def test_b(self):
        print('---用例b執行---')
    def test_c(self):
        print('---用例c執行---')
if __name__ == '__main__':
    pytest.main(['-s', 'test_abc.py'])

  

usefixtures與傳fixture區別

 如果fixture有返回值,那么usefixture就無法獲取到返回值,這個是裝飾器usefixture與用例直接傳fixture參數的區別。

當fixture需要用到return出來的參數時,只能講參數名稱直接當參數傳入,不需要用到return出來的參數時,兩種方式都可以。

 

 fixture第三個例子(默認設置為運行,作用域是function)

import pytest
@pytest.fixture(scope='function',autouse=True) # 作用域設置為function,自動運行
def before():
    print("------->before")
class Test_ABC:
    def setup(self):
        print("------->setup")
    def test_a(self):
        print("------->test_a")
        assert 1
    def test_b(self):
        print("------->test_b")
        assert 1
if __name__ == '__main__':
        pytest.main(["-s", "test_abc.py"])

  

 

 fixture第五個例子(設置作用域為class)

import pytest
@pytest.fixture(scope='class',autouse=True) # 作用域設置為class,自動運行
def before():
    print("------->before")
class Test_ABC:
    def setup(self):
        print("------->setup")
    def test_a(self):
        print("------->test_a")
        assert 1
    def test_b(self):
        print("------->test_b")
        assert 1
if __name__ == '__main__':
    pytest.main(["-s","test_abc.py"])

 

 fixture第六個例子(返回值)

import pytest
@pytest.fixture()
def need_data():
    return 2  # 返回數字2
class Test_ABC:
    def test_a(self, need_data):
        print("------->test_a")
        assert need_data != 3  # 拿到返回值做一次斷言
if __name__ == '__main__':
    pytest.main(["-s",  "test_abc.py"])

 

 

 

import pytest
@pytest.fixture(params=[1, 2, 3])
def need_data(request):  # 傳入參數request 系統封裝參數
    return request.param  # 取列表中單個值,默認的取值方式
class Test_ABC:
    def test_a(self, need_data):
        print("------->test_a")
        assert need_data != 3  # 斷言need_data不等於3
if __name__ == '__main__':
    pytest.main(["-s","test_abc.py"])

  發現結果運行了三次

 

fixture(設置作用域為module)

import pytest
@pytest.fixture(scope='module')
def test1():
    b = '男'
    print('傳出了%s, 且在當前py文件下執行一次!!!' % b)
    return b
def test_3(test1):
    name = '男'
    print('找到name')
    assert test1 == name
class Test_Case:
    def test_4(self, test1):
        sex = '男'
        print('找到sex')
        assert test1 == sex
if __name__ == '__main__':
    pytest.main(["-s","test_abc.py"])

  

 

 fixture(設置作用域為session)

fixture為session級別是可以跨.py模塊調用的,也就是當我們有多個.py文件的用例的時候,如果多個用例只需調用一次fixture,那就可以設置為scope="session",並且寫到conftest.py文件里。

conftest.py文件名稱時固定的,pytest會自動識別該文件。放到項目的根目錄下就可以全局調用了,如果放到某個package下,那就在改package內有效。

import pytest
# conftest.py

@pytest.fixture(scope='session')
def test1():
    a='door'
    print('獲取到%s' % a)
    return a

  

import pytest
# abc.py

def test3(test1):
    b = 'pen'
    print('找到b')
    assert test1 == b


if __name__ == '__main__':
    pytest.main(['-s', 'abc.py'])

  

import pytest
# abc1.py

class Test_Case:

    def test_4(self, test1):
        a = 'door'
        print('找到a')
        assert test1 == a

if __name__ == '__main__':
    pytest.main(['-s', 'abc1.py'])

  如果需要同時執行兩個py文件,可以在cmd中在文件py文件所在目錄下執行命令:pytest -s test_abc.py test_abc.py 

conftest.py的作用范圍

一個工程下可以建多個conftest.py的文件,一般在工程根目錄下設置的conftest文件起到全局作用。在不同子目錄下也可以放conftest.py的文件,作用范圍只能在改層級以及以下目錄生效。

 1.conftest在不同的層級間的作用域不一樣

 2.conftest是不能跨模塊調用的(這里沒有使用模塊調用)

 

 fixture自動使用autouse=True

當用例很多的時候,每次都傳這個參數,會很麻煩。fixture里面有個參數autouse,默認是False沒開啟的,可以設置為True開啟自動使用fixture功能,這樣用例就不用每次都去傳參了

平常寫自動化用例會寫一些前置的fixture操作,用例需要用到就直接傳該函數的參數名稱就行了。當用例很多的時候,每次都傳這個參數,會比較麻煩。
fixture里面有個參數autouse,默認是Fasle沒開啟的,可以設置為True開啟自動使用fixture功能,這樣用例就不用每次都去傳參了
設置autouse=True
autouse設置為True,自動調用fixture功能
start設置scope為module級別,在當前.py用例模塊只執行一次,autouse=True自動使用[圖片]open_home設置scope為function級別,
每個用例前都調用一次,自動使用

autouse設置為True,自動調用fixture功能

import pytest
@pytest.fixture(scope='module', autouse=True)
def test1():
    print('\n開始執行module')
@pytest.fixture(scope='class', autouse=True)
def test2():
    print('\n開始執行class')
@pytest.fixture(scope='function', autouse=True)
def test3():
    print('\n開始執行function')
def test_a():
    print('---用例a執行---')
def test_d():
    print('---用例d執行---')
class Test_Case:
    def test_b(self):
        print('---用例b執行---')
    def test_c(self):
        print('---用例c執行---')
if __name__ == '__main__':
    pytest.main(['-s', 'test_abc.py'])

  

 

 結果可以看到scope=class時也作用於class外的函數

fixture 之 params 使用示例

request 是pytest的內置 fixture ,主要用於傳遞參數

Fixture參數之params參數實現參數化:(可以為list和tuple,或者字典列表,字典元祖等)

import pytest
 
def read_yaml():
    return ['1','2','3']
 
@pytest.fixture(params=read_yaml())
def get_param(request):
    return request.param
 
def test_01(get_param):
    print('測試用例:'+get_param)
 
if __name__ == '__main__':
    pytest.main(['-s','test_abc.py'])
執行結果:

============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-6.0.2, py-1.9.0, pluggy-0.13.1
rootdir: E:\PycharmProjects\lianxi, configfile: pytest.ini
plugins: forked-1.3.0, html-1.22.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 3 items

test_abc.py 測試用例:1
.測試用例:2
.測試用例:3
.

------ generated html file: file://E:\PycharmProjects\lianxi\report.html ------
============================== 3 passed in 0.13s ==============================

  

注意:

1.此例中test01方法被執行了三次,分別使用的數據為'1','2','3',此結果類似於ddt數據驅動的功能。特別注意:這里的request參數名是固定的,然后request.param的param沒有s。

2.可以把return request.param改成yield request.param,yield也是返回的意思,它和return的區別在於return返回后后面不能接代碼,但是yield返回后,后面還可以接代碼。

 


免責聲明!

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



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