溫馨提示×

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

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

Pytest自動(dòng)化測(cè)試框架如何使用

發(fā)布時(shí)間:2023-03-16 10:44:24 來源:億速云 閱讀:85 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“Pytest自動(dòng)化測(cè)試框架如何使用”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Pytest自動(dòng)化測(cè)試框架如何使用”吧!

    Pytest和Unittest測(cè)試框架的區(qū)別?

    如何區(qū)分這兩者,很簡(jiǎn)單unittest作為官方的測(cè)試框架,在測(cè)試方面更加基礎(chǔ),并且可以再次基礎(chǔ)上進(jìn)行二次開發(fā),同時(shí)在用法上格式會(huì)更加復(fù)雜;而pytest框架作為第三方框架,方便的地方就在于使用更加靈活,并且能夠?qū)υ衭nittest風(fēng)格的測(cè)試用例有很好的兼容性,同時(shí)在擴(kuò)展上更加豐富,可通過擴(kuò)展的插件增加使用的場(chǎng)景,比如一些并發(fā)測(cè)試等;

    Pytest 安裝

    pip安裝:

    pip install pytest

    測(cè)試安裝成功:

    pytest --help
    
    py.test --help

    檢查安裝版本:

    pytest --version

    Pytest 示例

    Pytest編寫規(guī)則:

    • 測(cè)試文件以test_開頭(以_test為結(jié)尾)

    • 測(cè)試的類以Test開頭;

    • 測(cè)試的方法以test_開頭

    • 斷言使用基本的assert

    test_example.py

    def count_num(a: list) -> int:
        return len(a)
     
     
    def test_count():
        assert count_num([1, 2, 3]) != 3

    執(zhí)行測(cè)試:

    pytest test_example.py

    執(zhí)行結(jié)果:

    C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest>pytest test_example.py -v
    ================================================================= test session starts =================================================================
    platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- d:\coding\python3.6\python.exe
    cachedir: .pytest_cache
    rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
    plugins: Faker-8.11.0
    collected 1 item                                                                                                                                       
     
    test_example.py::test_count FAILED                                                                                                               [100%]
     
    ====================================================================== FAILURES =======================================================================
    _____________________________________________________________________ test_count ______________________________________________________________________
     
        def test_count():
    >       assert count_num([1, 2, 3]) != 3
    E       assert 3 != 3
    E        +  where 3 = count_num([1, 2, 3])
     
    test_example.py:11: AssertionError
    =============================================================== short test summary info ===============================================================
    FAILED test_example.py::test_count - assert 3 != 3
    ================================================================== 1 failed in 0.16s ==================================================================

    備注:

    • .代表測(cè)試通過,F(xiàn)代表測(cè)試失??;

    • -v顯示詳細(xì)的測(cè)試信息, -h顯示pytest命令詳細(xì)的幫助信息;

    標(biāo)記

    默認(rèn)情況下,pytest會(huì)在當(dāng)前目錄下尋找以test_為開頭(以_test結(jié)尾)的測(cè)試文件,并且執(zhí)行文件內(nèi)所有以test_為開頭(以_test為結(jié)尾)的所有函數(shù)和方法;

    指定運(yùn)行測(cè)試用例,可以通過::顯示標(biāo)記(文件名::類名::方法名)(文件名::函數(shù)名)

    pytest test_example3.py::test_odd

    指定一些測(cè)試用例測(cè)試運(yùn)行,可以使用-k模糊匹配

    pytest -k example

    通過pytest.mark.skip()或者pytest.makr.skipif()條件表達(dá)式,跳過指定的測(cè)試用例

    import pytest
     
    test_flag = False
     
    @pytest.mark.skip()
    def test_odd():
        num = random.randint(0, 100)
        assert num % 2 == 1
     
     
    @pytest.mark.skipif(test_flag is False, reason="test_flag is False")
    def test_even():
        num = random.randint(0, 1000)
        assert num % 2 == 0

    通過pytest.raises()捕獲測(cè)試用例可能拋出的異常

    def test_zero():
        num = 0
        with pytest.raises(ZeroDivisionError) as e:
            num = 1/0
        exc_msg = e.value.args[0]
        print(exc_msg)
        assert num == 0

    預(yù)先知道測(cè)試用例會(huì)失敗,但是不想跳過,需要顯示提示信息,使用pytest.mark.xfail()

    @pytest.mark.xfail()
    def test_sum():
        random_list = [random.randint(0, 100)  for x in range(10)]
        num = sum(random_list)
        assert num < 20

    對(duì)測(cè)試用例進(jìn)行多組數(shù)據(jù)測(cè)試,每組參數(shù)都能夠獨(dú)立執(zhí)行一次(可以避免測(cè)試用例內(nèi)部執(zhí)行單組數(shù)據(jù)測(cè)試不通過后停止測(cè)試)

    @pytest.mark.parametrize('num,num2', [(1,2),(3,4)])
    def test_many_odd(num: int, num2: int):
        assert num % 2 == 1
        assert num2 % 2 == 0

    固件(Fixture)

    固件就是一些預(yù)處理的函數(shù),pytest會(huì)在執(zhí)行測(cè)試函數(shù)前(或者執(zhí)行后)加載運(yùn)行這些固件,常見的應(yīng)用場(chǎng)景就有數(shù)據(jù)庫(kù)的連接和關(guān)閉(設(shè)備連接和關(guān)閉)

    簡(jiǎn)單使用

    import pytest
     
    @pytest.fixture()
    def postcode():
        return "hello"
    
    def test_count(postcode):
        assert postcode == "hello"

    按照官方的解釋就是當(dāng)運(yùn)行測(cè)試函數(shù),會(huì)首先檢測(cè)運(yùn)行函數(shù)的參數(shù),搜索與參數(shù)同名的fixture,一旦pytest找到,就會(huì)運(yùn)行這些固件,獲取這些固件的返回值(如果有),并將這些返回值作為參數(shù)傳遞給測(cè)試函數(shù);

    預(yù)處理和后處理

    接下來進(jìn)一步驗(yàn)證關(guān)于官方的說法:

    import pytest
     
    @pytest.fixture()
    def connect_db():
        print("Connect Database in .......")
        yield
        print("Close Database out .......")
     
    def read_database(key: str):
        p_info = {
            "name": "zhangsan",
            "address": "China Guangzhou",
            "age": 99
        }
        return p_info[key]
     
    def test_count(connect_db):
        assert read_database("name") == "zhangsan"

    執(zhí)行測(cè)試函數(shù)結(jié)果:

    ============================= test session starts =============================
    platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
    cachedir: .pytest_cache
    rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
    plugins: Faker-8.11.0
    collecting ... collected 1 item
     
    test_example.py::test_count Connect Database in .......
    PASSED                                       [100%]Close Database out .......
     
     
    ============================== 1 passed in 0.07s ==============================

    備注:

    • 首先從結(jié)果上看驗(yàn)證了官方的解釋,pytest執(zhí)行測(cè)試函數(shù)前會(huì)尋找同名的固件加載運(yùn)行;

    • connect_db固件中有yield,這里pytest默認(rèn)會(huì)判斷yield關(guān)鍵詞之前的代碼屬于預(yù)處理,會(huì)在測(cè)試前執(zhí)行,yield之后的代碼則是屬于后處理,將在測(cè)試后執(zhí)行;

    作用域

    從前面大致了解了固件的作用,抽離出一些重復(fù)的工作方便復(fù)用,同時(shí)pytest框架中為了更加精細(xì)化控制固件,會(huì)使用作用域來進(jìn)行指定固件的使用范圍,(比如在這一模塊中的測(cè)試函數(shù)執(zhí)行一次即可,不需要模塊中的函數(shù)重復(fù)執(zhí)行)更加具體的例子就是數(shù)據(jù)庫(kù)的連接,這一連接的操作可能是耗時(shí)的,我只需要在這一模塊的測(cè)試函數(shù)運(yùn)行一次即可,不需要每次都運(yùn)行。

    而定義固件是,一般通過scop參數(shù)來聲明作用,常用的有:

    • function: 函數(shù)級(jí),每個(gè)測(cè)試函數(shù)都會(huì)執(zhí)行一次固件;

    • class: 類級(jí)別,每個(gè)測(cè)試類執(zhí)行一次,所有方法都可以使用;

    • module: 模塊級(jí),每個(gè)模塊執(zhí)行一次,模塊內(nèi)函數(shù)和方法都可使用;

    • session: 會(huì)話級(jí),一次測(cè)試只執(zhí)行一次,所有被找到的函數(shù)和方法都可用。

    import pytest
      
    @pytest.fixture(scope="function")
    def func_scope():
        print("func_scope")
      
    @pytest.fixture(scope="module")
    def mod_scope():
        print("mod_scope")
     
    @pytest.fixture(scope="session")
    def sess_scope():
        print("session_scope") 
     
    def test_scope(sess_scope, mod_scope, func_scope):
        pass
     
    def test_scope2(sess_scope, mod_scope, func_scope):
        pass

    執(zhí)行結(jié)果:

    ============================= test session starts =============================
    platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
    cachedir: .pytest_cache
    rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
    plugins: Faker-8.11.0
    collecting ... collected 2 items
     
    test_example2.py::test_scope session_scope
    mod_scope
    func_scope
    PASSED                                      [ 50%]
    test_example2.py::test_scope2 func_scope
    PASSED                                     [100%]
     
    ============================== 2 passed in 0.07s ==============================

    從這里可以看出module,session作用域的固件只執(zhí)行了一次,可以驗(yàn)證官方的使用介紹

    自動(dòng)執(zhí)行

    有人可能會(huì)說,這樣子怎么那么麻煩,unittest框架中直接定義setUp就能自動(dòng)執(zhí)行預(yù)處理,同樣的pytest框架也有類似的自動(dòng)執(zhí)行; pytest框架中固件一般通過參數(shù)autouse控制自動(dòng)運(yùn)行。

    import pytest
     
    @pytest.fixture(scope='session', autouse=True)
    def connect_db():
       print("Connect Database in .......")
       yield
       print("Close Database out .......")
     
     
    def test1():
       print("test1")
     
     
    def test2():
       print("test")

    執(zhí)行結(jié)果:

    ============================= test session starts =============================
    platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
    cachedir: .pytest_cache
    rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
    plugins: Faker-8.11.0
    collecting ... collected 2 items
     
    test_example.py::test1 Connect Database in .......
    PASSED                                            [ 50%]test1
     
    test_example.py::test2 PASSED                                            [100%]test
    Close Database out .......
     
     
    ============================== 2 passed in 0.07s ==============================

    從結(jié)果看到,測(cè)試函數(shù)運(yùn)行前后自動(dòng)執(zhí)行了connect_db固件;

    參數(shù)化

    前面簡(jiǎn)單的提到過了@pytest.mark.parametrize通過參數(shù)化測(cè)試,而關(guān)于固件傳入?yún)?shù)時(shí)則需要通過pytest框架中內(nèi)置的固件request,并且通過request.param獲取參數(shù)

    import pytest
     
    @pytest.fixture(params=[
        ('redis', '6379'),
        ('elasticsearch', '9200')
    ])
    def param(request):
        return request.param
     
     
    @pytest.fixture(autouse=True)
    def db(param):
        print('\nSucceed to connect %s:%s' % param)
     
        yield
     
        print('\nSucceed to close %s:%s' % param)
     
    def test_api():
        assert 1 == 1

    執(zhí)行結(jié)果:

    ============================= test session starts =============================
    platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
    cachedir: .pytest_cache
    rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
    plugins: Faker-8.11.0
    collecting ... collected 2 items
     
    test_example.py::test_api[param0] 
    Succeed to connect redis:6379
    PASSED                                 [ 50%]
    Succeed to close redis:6379
     
    test_example.py::test_api[param1] 
    Succeed to connect elasticsearch:9200
    PASSED                                 [100%]
    Succeed to close elasticsearch:9200
     
     
    ============================== 2 passed in 0.07s ==============================

    這里模擬連接redis和elasticsearch,加載固件自動(dòng)執(zhí)行連接然后執(zhí)行測(cè)試函數(shù)再斷開連接。

    感謝各位的閱讀,以上就是“Pytest自動(dòng)化測(cè)試框架如何使用”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)Pytest自動(dòng)化測(cè)試框架如何使用這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

    向AI問一下細(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