1. 程式人生 > 實用技巧 >pytest進階使用

pytest進階使用

3. pytest進階使用

3.1 命令列引數

3.1.1 執行引數

Pytest的執行有很多引數,使用幫助檢視:

pytest -h

常用引數:

引數說明
-v 可以輸出用例更加詳細的執行資訊,比如用例所在的檔案及用例名稱
-s 輸入我們用例中的調式資訊,比如print的列印資訊等
-x 遇到失敗的用例立即停止
-maxfail 用例失敗達到一定個數時停止執行pytest --maxfail=num
-m 執行有@pytest.mark.標記名 的測試用例
-k 選擇部分測試,匹配給出的表示式;eg: pytest -k “raises and not delete”(執行所有名字中包含 raises但不包含delete的測試)
–collect-only 只收集用例
pytest -sv test_demo.py 

3.1.2 Mark標籤

可以對測試用例打標籤,在執行測試用例的時候,可根據標籤名來過濾要執行的用例

方式:在測試用例/測試類前加上:@pytest.mark.標記名

import pytest
class Test_Demo():
    @pytest.mark.demo
    def test_demo(self):
        a = 5
        b = -1
        assert a != b
        print("我的第一個測試用例")
    @pytest.mark.smoke
    def test_two(self):
        a = 2
        b = -1
        assert a != b
        print("我的第二個測試用例")

也可以在一個用例上打多個標籤,多次使用@pytest.mark.標籤名

@pytest.mark.demo
@pytest.mark.smoke
def test_add_02():
    b = 1 + 2
    assert 0 == b

執行:

pytest -m 標籤名

註冊標籤消除執行warning:

  1. 建立pytest.ini檔案,在檔案中按如下方式新增標籤名:
[pytest]
markers = demo
          smoke             

3.2 資料驅動入門

3.2.1 引數化

在測試用例的前面加上:

@pytest.mark.parametrize("引數名",列表資料)
  • 引數名:作為測試用例的引數. 字串格式,多個引數中間用逗號隔開。
  • 列表資料:一組測試資料。list格式,多組資料用元組型別,list的每個元素都是一個元組,元組裡的每個元素和按引數順序一一對應。

3.2.2 引數化演練

import pytest
def add_function(a,b):
    return a+b
@pytest.mark.parametrize("a,b,expected",
                         [(3,5,8),
                           (-1,-2,-3),
                           (100,200,300),
                         ])
def test_add(a,b,expected):
    assert add_function(a,b) == expected

3.2.3 引數加別名

pytest執行後,會使用輸入資料來作為用例的標題,但是這樣不便於我們檢視。可以新增ids引數指定用例說明。

import pytest
def add_function(a,b):
    return a+b
@pytest.mark.parametrize("a,b,expected",
                         [(3,5,8),
                           (-1,-2,-3),
                           (100,200,300),
                         ],ids=["int","minus","bigint"])
def test_add(a,b,expected):
    assert add_function(a,b) == expected

3.2.4 引數組合

若要獲得多個引數化引數的所有組合,可以堆疊引數化裝飾器

import pytest
@pytest.mark.parametrize("a", [0, 1])
@pytest.mark.parametrize("b", [2, 3])
def test_foo(a, b):
    print("測試資料組合:a->%s, b->%s" % (a, b))

執行結果

test_demo.py::test_foo[2-0] 測試資料組合:a->0, b->2 PASSED
test_demo.py::test_foo[2-1] 測試資料組合:a->1, b->2 PASSED
test_demo.py::test_foo[3-0] 測試資料組合:a->0, b->3 PASSED
test_demo.py::test_foo[3-1] 測試資料組合:a->1, b->3 PASSED

3.2.5 使用yaml檔案實現用例資料引數化

注意:使用之前需要在pycharm中安裝PyYAML

載入yaml檔案:

yaml.safe_load(open("./data.yml"))
import pytest
import yaml
def add_function(a,b):
    return a+b
@pytest.mark.parametrize("a,b,expected",
                         yaml.safe_load(open("./data.yml"))["datas"],
                         ids=yaml.safe_load(open("./data.yml"))["myid"])
def test_add(a,b,expected):
    assert add_function(a,b) == expected

data.yml檔案:

datas:
  -
    - 3
    - 5
    - 8
  -
    - -1
    - -2
    - -3
  -
    - 100
    - 200
    - 300
myid:
  - "int"
  - "minus"
  - "bigint"

讀取資料抽離出來改造:

import pytest
import yaml

def get_datas():
    with open("./data.yml") as f:
        datas = yaml.safe_load(f)
        print(datas)
        add_datas=datas["datas"]
        add_ids=datas["myid"]
        return [add_datas,add_ids]

def add_function(a,b):
    return a+b
@pytest.mark.parametrize("a,b,expected",
                         get_datas()[0],
                         ids=get_datas()[1])
def test_add(a,b,expected):
    assert add_function(a,b) == expected

3.2.6 使用yaml檔案實現用例步驟引數化

steps.yml

- step1
- step2
- step3

import pytest
import yaml

def step1():
    print("開啟瀏覽器")
def step2():
    print("註冊新賬號")
def step3():
    print("登入新賬號")
# 解析測試步驟檔案
def steps(path):
    with open(path) as f:
        steps = yaml.safe_load(f)
    for step in steps:
        if "step1" in step:
            step1()
        elif "step2" in step:
            step2()
        elif "step3" in step:
            step3()

def test_foo():
    steps("./steps.yml")

https://github.com/ceshiren/HogwartsSDET12/blob/master/appium_xueqiu/page/base_page.py1

3.3 fixture裝置的使用

3.3.1 fixture使用背景

前面講了setup、teardown可以實現在執行用例前或結束後加入一些操作,但這種都是針對整個指令碼全域性生效的。(註釋:setup相當於這個個檔案使用,每個檔案裡用;fixtire是對每個用例)
如果有以下場景:用例 1 需要先登入,用例 2 不需要登入,用例 3 需要先登入。很顯然無法用 setup 和 teardown 來實現。fixture可以讓我們自定義測試用例的前置條件,並且可以跨檔案使用。

3.3.2 fixture的優勢

  • 命名方式靈活,不侷限於 setup 和teardown 這幾個命名
  • conftest.py 配置裡可以實現資料共享,不需要 import 就能自動找到fixture
  • scope=“session” 以實現多個.py跨檔案共享

3.3.3@pytest.fixtrue()快速體驗

  1. 直接使用
import pytest
@pytest.fixture()
def myfixture():
    print("執行myfixture")

class Test_firstFile():

    def test_one(self):
        print("執行test_one")
        assert 2+3==5

    def test_two(self,myfixture):
        print("執行test_two")
        assert 1==1

    def test_three(self):
        print("執行test_three")
        assert 1+1==2
  1. 通過conftest.py檔案

conftest.py這個檔名是固定的,不可以更改。
使用的時候不需要匯入conftest.py,會自動尋找.

演練:建立一個conftest.py檔案

import pytest
@pytest.fixture()
def myfixture():
    print("執行myfixture")

###3.3.4 fixture中使用autouse
如果我們想要模組中每個測試函式都是用宣告好的前置函式,每個測試函式都傳入引數或新增裝飾器,是不是很不方便?這時我們可以使用@pytest.fixture()中的引數autouse(自動使用),將其設為true(預設為false),這樣每個測試函式都會自動呼叫該前置函數了。

語法:

@pytest.fixture(autouse="true")

3.3.5 fixture中使用作用域

語法:

@pytest.fixture(scope ="class")

scope引數有四種選擇:function(測試函式級別),class(測試類級別),module(測試模組“.py”級別),session(多個檔案級別)。預設是function級別。

3.3.6 fixture中使用引數

fixture函式可以引數化,在這種情況下,它們將被多次呼叫,每次執行一組相關測試,即依賴於這個fixture的測試,測試函式通常不需要知道它們的重新執行。

fixture函式需要傳入特殊的request物件

函式裡面可通過request.param訪問每個引數的值

也可加ids指定引數名字

import pytest
@pytest.fixture(params=["引數1","引數2"])
def myfixture(request):
    print("執行testPytest裡的前置函式,%s" % request.param)

3.3.7 fixture中返回引數

import pytest
@pytest.fixture(params=["引數1","引數2"])
def myfixture(request):
    return request.param
def test_print_param(myfixture):
    print("執行test_two")
    print(myfixture)
    assert 1==1

輸出:

PASSED                    [ 50%]執行test_two 
引數1
PASSED                    [100%]執行test_two
引數2

3.3.8 fixture中使用yield實現teardown

fixture裡面的teardown用yield來喚醒teardown的執行

import pytest
@pytest.fixture(params=["引數1","引數2"])
def connect_db(request):
    print("開始連線資料庫!")
    yield request.param
    print("執行teardown,關閉資料庫連線")

def test_print_param(connect_db):
    print("執行test_two")
    print(connect_db)
    assert 1==1

3.4 給pytest.ini新增更多配置

[pytest]
markers = demo
          smoke
addopts = -sv
;自定義測試檔案命名規則
python_files = check*
;自定義測試類命名規則
python_classes = Test*
;自定義測試方法命名規則
python_functions = test_* check_*

4 pytest實用外掛介紹

可在這裡搜尋使用方式:

https://pypi.org/project/pip/

##4.1. 用例失敗後自動重新執行:pytest-rerunfailures
安裝外掛:

pip install pytest-rerunfailures

使用方法:

pytest test_x.py --reruns=n  #失敗後重執行的次數

同時也可以在指令碼中指定定義重跑的次數,這個時候在執行的時候,就無需加上 --reruns 這個引數

@pytest.mark.flaky(reruns=6, reruns_delay=2)
    def test_example(self):
        print(3)
        assert random.choice([True, False])

4.2 多重校驗:pytest-assume

pytest中可以用python的assert斷言,也可以寫多個斷言,但一個失敗,後面的斷言將不再執行。

安裝外掛:

pip install pytest-assume

使用方法:

def test_simple_assume(x, y):
    pytest.assume(x == y)
    pytest.assume(True)
    pytest.assume(False)

4.3 分散式併發執行:pytest-xdist

pytest-xdist的出現就是為了讓自動化測試用例可以分散式執行,從而節省自動化測試時間

分散式執行用例的設計原則:

  1. 用例之間是獨立的,用例之間沒有依賴關係,用例可以完全獨立執行【獨立執行】
  2. 用例執行沒有順序,隨機順序都能正常執行【隨機執行】
  3. 每個用例都能重複執行,執行結果不會影響其他用例【不影響其他用例】

安裝外掛:

pip install pytest-xdist

使用方法:

多cpu並行執行用例,直接加個-n引數即可,後面num引數就是並行數量,比如num設定為3

pytest -n 3

4.4 控制用例的執行順序:pytest-ordering

安裝外掛:

pip install pytest-ordering

使用方法:

import pytest

@pytest.mark.run(order=2)
def test_foo():
    assert True

@pytest.mark.run(order=1)
def test_bar():
    assert True

注意:儘量不要讓測試用例有順序,儘量不要讓測試用例有依賴!

4.5 hook(鉤子)函式定製和擴充套件外掛【瞭解】

官網:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html

pytest_collection_modifyitems

Pytest在收集完所有測試用例後呼叫該鉤子方法。我們可以定製化功能實現:

  1. 自定義用例執行順序
  2. 解決編碼問題(中文測試用例名稱)
  3. 自動新增標籤

例如:
conftest.py裡面:

新增:


def pytest_collection_modifyitems(session, config, items):
    print(type(items))
    items.reverse()
    for item in items:
        item.name = item.name.encode('utf-8').decode('unicode-escape')
        item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')

        if "add" in item._nodeid:
            item.add_marker(pytest.mark.add)
        if "div" in item._nodeid:
            item.add_marker(pytest.mark.div)


5 Allure

安裝:https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/2.13.7/

  • mac直接brew install allure安裝
  • windows直接下載zip包,解壓後把bin路徑配置到path裡面,使用allure.bat
  • 命令列輸入allure檢視安裝是否成功。

pytest裡面安裝allure-pytest
使用allure:

 pytest --alluredir ./report

生成的result記錄詳細結果,中間結果。最終結果:

allure serve ./report

起了一個服務,後續會進階學習。
暫時服務,長期服務用jenkins,或者在本地搭建網站服務:Django。
python mange.py runserver (http://127.0.0.1:8000)

生成html檔案:

allure generate ./report

生成html檔案,open in chrome