• 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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest .	est_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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest .	est_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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest .	est_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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest -m smoke .	est_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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    collected 2 items
    
    test_02.py ..                                                                       [100%]
    ============================ 2 passed, 4 warnings in 0.12s ====================================
    
    PS C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest -m testValueError .	est_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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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" .	est_02.py
    pytest -m "testValueError and not testTypeError" .	est_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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest -v .	est_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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    collected 2 items
    
    test_02.py::test_addValueError PASSED                                                                      [ 50%]
    test_02.py::test_addTypeError SKIPPED                                                                      [100%]
    

    尽管跳过的原因不是必须写,但还是建议在实际项目尽可能的写上,方便知道跳过的原因,如果想知道跳过的详细原因,可使用参数 -rs

    PS C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest -rs -v .	est_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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02> pytest  .	est_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:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 .PytestStudyLesson02	est_01.py
    

    4.6.3 单个测试函数

        运行单个测试函数,只需要在文件名后面添加::符号和函数名即可,如下所示:

    pytest .	est_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 .	est_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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 .	est_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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 .	est_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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 .	est_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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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 filespythonpython.exe
    cachedir: .pytest_cache
    rootdir: C:UsersSurpassDocumentsPycharmProjectsPytestStudyLesson02
    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

  • 相关阅读:
    java读写文件
    idea文件全部变红, 文件全部红色
    PowerDesigner连接MySQL数据库
    mysql 使用ip地址连接不上;MySQL 可以用localhost 连接,但不能用IP连接的问题,局域网192.168.*.* 无法连接mysql
    powerdesigner连接MySQL数据库时出现Non SQL Error : Could not load class com.mysql.jdbc.Driver
    JSP的九大对象和四大作用域
    C#面试问题及答案
    数据库面试题及答案
    多态的深入理解
    面向对象编程----继承---笔记
  • 原文地址:https://www.cnblogs.com/surpassme/p/13252315.html
Copyright © 2020-2023  润新知