Pytest04-編寫測試函數

4.編寫測試函數

4.1 使用assert聲明

    使用pytest編寫測試時,若需要傳遞測試失敗信息,可以直接使用Pytho自帶的assert關鍵字。pytest與其他測試框架如unittest的區別如下所示:

pytest unittest
assert something assertTrue(something)
assert a==b assertEqual(a,b)
assert a<=b assertLessEqual(a,b)
... ...

    pytest中assert主要有以下特點

  • 1.assert 後面可以添加任何表達式,若表達式的結果通過bool轉換結果爲True,則代表測試通過
  • 2.pytest 可以重寫assert關鍵字。pytest可截斷對原生assert的調用,替換爲pytest定義的assert,從而提供更多的詳細失敗信息
import pytest

def addItemToList(item):
    tmpList=[]
    tmpList.append(item)
    return tmpList


def test_addItemToList():
    t1=addItemToList("a")
    t2=addItemToList("b")
    assert t1==t2

運行結果如下所示:

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest .\test_01.py
=============================test session starts ====================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 1 item

test_01.py F                                                                [100%]

================================== FAILURES ======================================
___________________________test_addItemToList ____________________________________

    def test_addItemToList():
        t1=addItemToList("a")
        t2=addItemToList("b")
>       assert t1==t2
E       AssertionError: assert ['a'] == ['b']
E         At index 0 diff: 'a' != 'b'
E         Use -v to get the full diff

test_01.py:12: AssertionError
=================================== short test summary info =========================
FAILED test_01.py::test_addItemToList - AssertionError: assert ['a'] == ['b']
====================================1 failed in 0.29s ==============================

    在上面的運行結果中,失敗的測試用例在行首會有一個 > 來標識。以E開頭的行是pytest提供的額外判定信息,用於幫助瞭解異常的具體信息。

4.2 預期異常

    在Python後來的版本,增加了函數參數註解功能,即在定義一個參數後,後面可直接聲明參數的數據類型,方便其他人員知道如何調用這個函數,如下所示:

def add(x:int,y:int)->int:
    return x+y

    爲確保像這樣的函數,在發生類型錯誤時,可以拋出異常,可以使用with pytest.raises(< expected exception >),如下所示:

def add(x:int,y:int)->int:
    if not isinstance(x,(int,)) or not isinstance(y,(int,)):
        raise TypeError("args must be int")
    else:
        return x+y

def test_add():
    with pytest.raises(TypeError):
        add("1","2")

運行結果如下所示:

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest .\test_01.py
==============================test session starts ================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 1 item

test_01.py .                                                              [100%]

=================================1 passed in 0.08s ===============================

    測試用例中test_add()有with pytest.raises(TypeError)聲明,則意味着無論with中的內容是什麼,都至少會產生TypeError異常。如果測試通過,則說明確實發生了預期的TypeError異常,如果拋出的是其他類型的異常,則與預期不一致,測試失敗。

    在上面的測試用例中,僅檢驗了傳參數據的類型異常,也可以檢查值異常,比如在檢驗一個參數的數據類型之後,也可以再檢驗其內容,爲校驗異常消息是否符合預期,可以增加as exInfo語句得到異常消息的值,再進行校驗,示例如下所示:

def add(x:int,y:int,operator:str)->int:
    if not isinstance(x,(int,)) or not isinstance(y,(int,)) or not isinstance(operator,(str,)):
        raise TypeError("args must be int")
    if operator=="+":
        return x + y
    elif operator=="-":
        return x - y
    else:
        raise ValueError("operator must be '+' or '-' ")

def test_add():
    with pytest.raises(ValueError) as exInfo:
        add(1,2,"*")
    exInfo=exInfo.value.args[0]
    expectInfo="operator must be '+' or '-' "
    assert expectInfo== exInfo

運行結果如下所示:

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest .\test_01.py
=============================test session starts ============================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 1 item

test_01.py .                                                      [100%]

============================1 passed in 0.13s ================================

4.3 測試函數標記

    pytest提供了標記機制,允許使用marker對測試函數進行標記,一個測試函數可以有多個marker,一個marker也可以用來標記多個測試函數

對測試函數進行標記,通常使用的場景爲冒煙測試,一般情況下冒煙測試不需要跑全部的測試用例,只需要選擇關鍵的點進行測試,這個時候只跑被標記爲冒煙測試的測試用例,會省很多時間。

    示例如下所示:

import pytest

def add(x:int,y:int,operator:str)->int:
    if not isinstance(x,(int,)) or not isinstance(y,(int,)) or not isinstance(operator,(str,)):
        raise TypeError("args must be int")
    if operator=="+":
        return x + y
    elif operator=="-":
        return x - y
    else:
        raise ValueError("operator must be '+' or '-' ")

@pytest.mark.testValueError
@pytest.mark.smoke
def test_addValueError():
    with pytest.raises(ValueError) as exInfo:
        add(1,2,"*")
    exInfo=exInfo.value.args[0]
    expectInfo="operator must be '+' or '-' "
    assert expectInfo== exInfo

@pytest.mark.testTypeErrorTest
@pytest.mark.smoke
def test_addTypeError():
    with pytest.raises(TypeError):
        add("1","2","+")

    現在只需要在命令中指定-m markerName,就可以運行指定的測試用例,如下所示:

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest -m smoke .\test_02.py
=========================test session starts ===============================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 2 items

test_02.py ..                                                                       [100%]
============================ 2 passed, 4 warnings in 0.12s ====================================

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest -m testValueError .\test_02.py
==============================test session starts ==============================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 2 items / 1 deselected / 1 selected

test_02.py .                                                                        [100%]
========================= 1 passed, 1 deselected, 4 warnings in 0.04s ===========================

    針對上面示例,可以得出以下結論

1.pytest.mark.markName:markName由用戶自行定義,並非pytest內置
2.-m:後面也可以使用表達式,可以在標記之間添加and、or、not等關鍵字,如下所示:

pytest -m "testValueError and testTypeError" .\test_02.py
pytest -m "testValueError and not testTypeError" .\test_02.py

4.4 跳過測試

    pytest內置了一些標記,如skip、skipif、xfail。其中skip、skipif允許跳過不希望運行的測試。示例如下所示:

1.要直接跳過某一個測試函數,可以使用pytest.mark.skip()裝飾器即可

import pytest

def add(x:int,y:int,operator:str)->int:
    if not isinstance(x,(int,)) or not isinstance(y,(int,)) or not isinstance(operator,(str,)):
        raise TypeError("args must be int")
    if operator=="+":
        return x + y
    elif operator=="-":
        return x - y
    else:
        raise ValueError("operator must be '+' or '-' ")

@pytest.mark.testValueError
@pytest.mark.smoke
def test_addValueError():
    with pytest.raises(ValueError) as exInfo:
        add(1,2,"*")
    exInfo=exInfo.value.args[0]
    expectInfo="operator must be '+' or '-' "
    assert expectInfo== exInfo

@pytest.mark.skip(reason="skip this case")
def test_addTypeError():
    with pytest.raises(TypeError):
        add("1","2","+")

運行結果如下所示:

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest -v .\test_02.py
==========================test session starts =================================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 2 items

test_02.py::test_addValueError PASSED                                                      [ 50%]
test_02.py::test_addTypeError SKIPPED                                                      [100%]

2.添加跳過的原因和條件,可以使用pytest.mark.skipif()裝飾器即可

    如果有一些測試,只有在滿足特定條件的情況下,才被跳過,這時候則可以使用pytest.mark.skipif(),示例如下所示:

import pytest

def add(x:int,y:int,operator:str)->int:
    """this is sample case"""
    if not isinstance(x,(int,)) or not isinstance(y,(int,)) or not isinstance(operator,(str,)):
        raise TypeError("args must be int")
    if operator=="+":
        return x + y
    elif operator=="-":
        return x - y
    else:
        raise ValueError("operator must be '+' or '-' ")

@pytest.mark.testValueError
@pytest.mark.smoke
def test_addValueError():
    with pytest.raises(ValueError) as exInfo:
        add(1,2,"*")
    exInfo=exInfo.value.args[0]
    expectInfo="operator must be '+' or '-' "
    assert expectInfo== exInfo

@pytest.mark.skipif(add.__doc__=="this is sample case",reason="skip this case")
def test_addTypeError():
    with pytest.raises(TypeError):
        add("1","2","+")

運行結果如下所示:

platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 2 items

test_02.py::test_addValueError PASSED                                                                      [ 50%]
test_02.py::test_addTypeError SKIPPED                                                                      [100%]

儘管跳過的原因不是必須寫,但還是建議在實際項目儘可能的寫上,方便知道跳過的原因,如果想知道跳過的詳細原因,可使用參數 -rs

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest -rs -v .\test_02.py
======================test session starts ====================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 2 items

test_02.py::test_addValueError PASSED                                                       [ 50%]
test_02.py::test_addTypeError SKIPPED                                                       [100%]
==================================short test summary info =================================
SKIPPED [1] test_02.py:23: skip this case
==========================1 passed, 1 skipped, 2 warnings in 0.04s ========================

4.5 標記預期失敗的測試

    使用skip和skipif,在滿足條件的下,會直接跳過,而不會執行。使用xfail標記,則是預期運行失敗,如下所示:

import pytest

def add(x:int,y:int,operator:str)->int:
    """this is sample case"""
    if not isinstance(x,(int,)) or not isinstance(y,(int,)) or not isinstance(operator,(str,)):
        raise TypeError("args must be int")
    if operator=="+":
        return x + y
    elif operator=="-":
        return x - y
    else:
        raise ValueError("operator must be '+' or '-' ")

@pytest.mark.xfail
def test_addValueError():
    with pytest.raises(ValueError) as exInfo:
        add(1,2,"*")
    exInfo=exInfo.value.args[0]
    expectInfo="operator must be '+' or '-' "
    assert expectInfo!= exInfo

@pytest.mark.xfail(add.__doc__=="this is sample case",reason="skip this case")
def test_addTypeError():
    with pytest.raises(TypeError):
        add("1","2","+")

運行結果如下所示:

PS C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02> pytest  .\test_02.py
============================test session starts ===================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 2 items

test_02.py xX                                                                        [100%]

======================= 1 xfailed, 1 xpassed in 0.19s ===============================
  • x代表XFAIL,意味着expect to fail(預期失敗,實際上也失敗)
  • X代表XPASS,意味着expect to fail but passed(預期失敗,實際上成功)

    對於標記爲xfail,但實際運行結果爲XPASS的測試,可以在pytest配置中強制指定爲FAIL,在pytest.ini文件按如下修改即可:

[pytest]
xfail_strict=true

4.6 運行測試子集

    前面主要介紹對測試函數進行標記及如何運行。而運行測試子集可以按目錄文件類中的測試,還可以選擇運行某一個測試用例(可能在文件中,也可以在類中)**。

4.6.1 單個目錄

    運行單個目錄下的所有測試,以目錄做爲參數即可,如下所示:

pytest --tb=no .\PytestStudy\

4.6.2 單個測試文件/模塊

    運行單個測試文件/模塊,以路徑名加文件名做爲參數即可,如下所示:

pytest --tb=no .\PytestStudy\Lesson02\test_01.py

4.6.3 單個測試函數

    運行單個測試函數,只需要在文件名後面添加::符號和函數名即可,如下所示:

pytest .\test_02.py::test_addTypeError

4.6.4 單個測試類

    測試類用於將某些相似的測試函數組合在一起,來看看以下示例:

import pytest

class Person:
    _age=28
    _name="Surpass"
    
    def __init__(self,age,name):
        self._name=name
        self._age=age
        
    @classmethod
    def getAge(cls):
        if not isinstance(cls._age,(int,)):
            raise TypeError("age must be integer")
        else:
            return cls._age
    
    @classmethod
    def getName(cls):
        if not isinstance(cls._name,(str,)):
            raise TypeError("name must be string")
        else:
            return cls._name

class TestPerson:
    
    def test_getAge(self):
        with pytest.raises(TypeError):
            Person.getAge("28")
            
    def test_getName(self):
        with pytest.raises(TypeError):
            Person.getName(123)

    以上測試類中的方法都是測試Person中的方法,因此可以放在一個測試類中,要運行該類,可以在文件名後面添加::符號和類名即可,與運行單個測試函數類似,如下所示:

 pytest .\test_03.py::TestPerson -v
========================== test session starts ===========================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 2 items

test_03.py::TestPerson::test_getAge PASSED                                          [ 50%]
test_03.py::TestPerson::test_getName PASSED                                         [100%]

============================= 2 passed in 0.04s ============================================

4.6.5 單個測試類中的測試方法

    如果不希望運行測試類中的所有測試方法,可以指定運行的測試方法名即,可以在文件名後面添加::類名::類中方法名即可,如下所示:

>>> pytest -v .\test_03.py::TestPerson::test_getName
=========================== test session starts ==================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 1 item

test_03.py::TestPerson::test_getName PASSED                                          [100%]

============================= 1 passed in 0.04s ===============================

4.6.6 用測試名劃分測試集合

    -k選項允許用一個表達式指定需要運行的測試,表達式可以匹配測試名或其子串,表達式中也可以包含and、or、not等。

    例如想運行目錄中,所有文件中測試函數名包含_add的測試函數,可按如下方式進行操作:

>>> pytest -v -k _add
======================== test session starts ===============================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 5 items / 2 deselected / 3 selected

test_01.py::test_add PASSED                                                         [ 33%]
test_02.py::test_addValueError XFAIL                                                [ 66%]
test_02.py::test_addTypeError XPASS                                                 [100%]

==================== 1 passed, 2 deselected, 1 xfailed, 1 xpassed in 0.14s ====================

4.7 參數化測試

4.7.1 參數化方式

    向函數傳值並校驗其輸出是軟件測試的常用手段,但大部分情況下,僅使用一組數據是無法充分測試函數功能。參數化測試允許傳遞多組數據,一旦發現測試失敗,pytest會及時拋出信息。
    要使用參數化測試,需要使用裝飾器pytest.mark.parametrize(args,argsvaules)來傳遞批量的參數。示例如下所示:

1.方式一

import pytest

def add(x:int,y:int)->int:
    return x+y

@pytest.mark.parametrize("paras",[(1,2),(3,5),(7,8),(10,-98)])
def test_add(paras):
    res=add(paras[0],paras[1])
    expect=paras[0]+paras[1]
    assert res==expect

運行結果如下所示:

>>> pytest -v .\test_04.py
================================================= test session starts =================================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 4 items

test_04.py::test_add[paras0] PASSED                               [ 25%]
test_04.py::test_add[paras1] PASSED                               [ 50%]
test_04.py::test_add[paras2] PASSED                               [ 75%]
test_04.py::test_add[paras3] PASSED                               [100%]

=====================4 passed in 0.10s ====================================

    在parametrize()中第一個參數字符串列表(paras),第二個參數是一個值列表,pytest會輪流對每個paras做測試,並分別報告每個測試用例的結果。

    parametrize()函數工作正常,那如果把paras替換爲鍵值對形式了,能否達到同樣的效果,如下所示:

2.方式二

import pytest

def add(x:int,y:int)->int:
    return x+y

@pytest.mark.parametrize(("x","y"),[(1,2),(3,5),(7,8),(10,-98)])
def test_add(x,y):
    res=add(x,y)
    expect=x+y
    assert res==expect

運行結果如下所示:

>>> pytest -v .\test_04.py
====================test session starts =================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 4 items

test_04.py::test_add[1-2] PASSED                                            [ 25%]
test_04.py::test_add[3-5] PASSED                                            [ 50%]
test_04.py::test_add[7-8] PASSED                                            [ 75%]
test_04.py::test_add[10--98] PASSED                                         [100%]

======================4 passed in 0.16s =============================

    如果傳入的參數具有標識性,則在輸出結果中也同樣具備可標識性,增強可讀性。也可以使用完整的測試標識(pytest術語爲node),如果標識符中包含空格,則需要使用引號。重新運行指定的測試如下所示:

>>> pytest -v test_04.py::test_add[1-2]
================================ test session starts =======================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 1 item

test_04.py::test_add[1-2] PASSED                                      [100%]

========================== 1 passed in 0.04s ===================================

3.方式三

    除了以上兩種方式之外,還可以使用如下方式進行參數化,如下所示:

import pytest

def add(x:int,y:int)->int:
    return x+y

paras=((1,2),(3,5),(7,8),(10,-98))
@pytest.mark.parametrize("p",paras)
def test_add(p):
    res=add(p[0],p[1])
    expect=p[0]+p[1]
    assert res==expect

運行結果如下所示

>>> pytest -v test_04.py
================================ test session starts ======================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 4 items

test_04.py::test_add[p0] PASSED                                          [ 25%]
test_04.py::test_add[p1] PASSED                                          [ 50%]
test_04.py::test_add[p2] PASSED                                          [ 75%]
test_04.py::test_add[p3] PASSED                                          [100%]

==============================4 passed in 0.14s ======================================

4.7.2 添加額外參數ids

1.方式一

    以上幾種雖然可以達到參數化的目的,但可讀性不太友好,爲改善可讀性,可以爲parametrize()引入一個額外的參數ids,使列表中每個元素都被標識。ids是一個字符串列表和數據對象列表和長度一致。如下所示:

import pytest

def add(x:int,y:int)->int:
    return x+y

paras=((1,2),(3,5),(7,8),(10,-98))

parasIds=[f"{x},{y}" for x,y in paras]

@pytest.mark.parametrize("p",paras,ids=parasIds)
def test_add(p):
    res=add(p[0],p[1])
    expect=p[0]+p[1]
    assert res==expect

運行結果如下所示

>>> pytest -v test_04.py
========================= test session starts ===================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 4 items

test_04.py::test_add[1,2] PASSED                                       [ 25%]
test_04.py::test_add[3,5] PASSED                                       [ 50%]
test_04.py::test_add[7,8] PASSED                                       [ 75%]
test_04.py::test_add[10,-98] PASSED                                    100%]

=================================== 4 passed in 0.11s ============================

    parametrize()不僅適於一般的測試函數,也可以適用類,在用於類中,則數據集會被傳遞給該類的所有方法,如下所示:

import pytest

paras=((1,2),(3,5),(7,8),(10,-98))
parasIds=[f"{x},{y}" for x,y in paras]

class Oper:
    _x=0
    _y=0

    def __int__(self,x,y):
        self._x=x
        self._y=y

    @classmethod
    def add(cls,x,y):
        return x+y

    @classmethod
    def sub(cls,x,y):
        return x-y

@pytest.mark.parametrize("p",paras,ids=parasIds)
class TestOper:
    def test_add(self,p):
        res=Oper.add(p[0],p[1])
        expect=p[0]+p[1]
        assert res==expect

    def test_sub(self,p):
        res = Oper.sub(p[0], p[1])
        expect = p[0] - p[1]
        assert res == expect

運行結果如下所示

>>> pytest -v test_04.py
============================= test session starts =============================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 8 items

test_04.py::TestOper::test_add[1,2] PASSED                                  [ 12%]
test_04.py::TestOper::test_add[3,5] PASSED                                  [ 25%]
test_04.py::TestOper::test_add[7,8] PASSED                                  [ 37%]
test_04.py::TestOper::test_add[10,-98] PASSED                               [ 50%]
test_04.py::TestOper::test_sub[1,2] PASSED                                  [ 62%]
test_04.py::TestOper::test_sub[3,5] PASSED                                  [ 75%]
test_04.py::TestOper::test_sub[7,8] PASSED                                  [ 87%]
test_04.py::TestOper::test_sub[10,-98] PASSED                               [100%]

============================ 8 passed in 0.13s ================================

2.方式二

    在給@pytest.mark.parametrize()裝飾器傳入參數列表時,還可以在參數值中定義一個id做爲標識,其語法格式如下所示:

@pytest.mark.parametrize(<value>,id="id")

    示例如下所示:

import pytest

class Oper:
    _x=0
    _y=0

    def __int__(self,x,y):
        self._x=x
        self._y=y

    @classmethod
    def add(cls,x,y):
        return x+y

    @classmethod
    def sub(cls,x,y):
        return x-y

@pytest.mark.parametrize("p",[pytest.param((1,2),id="id-1"),pytest.param((3,5),id="id-2"),
                              pytest.param((7,8),id="id-3"),pytest.param((10,-98),id="id-4")])
class TestOper:
    def test_add(self,p):
        res=Oper.add(p[0],p[1])
        expect=p[0]+p[1]
        assert res==expect

    def test_sub(self,p):
        res = Oper.sub(p[0], p[1])
        expect = p[0] - p[1]
        assert res == expect

運行結果如下所示

>>> pytest -v test_04.py
==============test session starts ====================================
platform win32 -- Python 3.7.6, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- d:\program files\python\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Surpass\Documents\PycharmProjects\PytestStudy\Lesson02
collected 8 items

test_04.py::TestOper::test_add[id-1] PASSED                             [ 12%]
test_04.py::TestOper::test_add[id-2] PASSED                             [ 25%]
test_04.py::TestOper::test_add[id-3] PASSED                             [ 37%]
test_04.py::TestOper::test_add[id-4] PASSED                             [ 50%]
test_04.py::TestOper::test_sub[id-1] PASSED                             [ 62%]
test_04.py::TestOper::test_sub[id-2] PASSED                             [ 75%]
test_04.py::TestOper::test_sub[id-3] PASSED                             [ 87%]
test_04.py::TestOper::test_sub[id-4] PASSED                             [100%]

=============================== 8 passed in 0.19s =============================

    在id不能被參數批量生成,需要自定義時,這個方法非常適用。

原文地址:https://www.cnblogs.com/surpassme/p/13252315.html

本文同步在微信訂閱號上發佈,如各位小夥伴們喜歡我的文章,也可以關注我的微信訂閱號:woaitest,或掃描下面的二維碼添加關注:
MyQRCode.jpg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章