pytest系列(2)--测试用例的组织及运行

1 pytest 测试用例自动发现原则

  • (1) 如果pytest 命令指定了目录参数,则从指定目录查找
  • (2) 如果pytest 命令没有通过参数形式指定目录,则从当前目录下查找是否有pytest.ini文件,如果有则从文件中查找 testpaths的值作为查找目录
  • (3) 如果在当前目录下没有找到pytest.ini文件,或者pytest.ini文件中没有配置testpaths值,则从当前目录递归查找
  • (4) 查找文件要求是test_*.py 或者 *_test.py
  • (5) 在文件中类的外面查找test开头的函数
  • (6) 在没有定义__init__方法的并且以Test开头的类中查找test开头的函数

新建如下文件结构:

ex_003
   |----ex_03_test.py
   |----ex_04test.py
   |----test_ex_01.py
   |----testex_02.py

每个文件中都编写如下相同的代码:


# 符合条件,文件中类外,test开头的函数
def test_function1():
    print("in test_function1")
    
# 符合条件,文件中类外,test开头的函数
def testfunction2():
    print("in testfunction2")
    
# 不符合条件,文件中类外,非test开头的函数
def function3_test():
    print("in function3_test")
    
# 不符合条件,文件中类外,非test开头的函数
def function4test():
    print("in function4test")
    
# 符合条件的类,类命名以Test开头,并且没有__init__.py文件
class TestClass1():
    
    # 符合条件,类中以test开头的函数
    def test_function1(self):
        print("in TestClass1.test_function1")

    # 符合条件,类中以test开头的函数
    def testfunction2(self):
        print("in TestClass1.testfunction2")

    # 不符合条件,类中非以test开头的函数
    def function3_test(self):
        print("in TestClass1.function3_test")

    # 不符合条件,类中非以test开头的函数
    def function4test(self):
        print("in TestClass1.function4test")
       
# 不符合条件的类,类命名虽然以Test开头,但是有__init__.py文件,此类中所有函数不会被pytest发现
class TestClass2():
    def __init__(self):
        pass
    def test_function1(self):
        print("in TestClass2.test_function1")

    def testfunction2(self):
        print("in TestClass2.testfunction2")

    def function3_test(self):
        print("in TestClass2.function3_test")

    def function4test(self):
        print("in TestClass2.function4test")
        
# 不符合条件的类,类命名非以Test开头,此类中所有测试函数不会被pytest发现
class Class3Test():

    def test_function1(self):
        print("in Class3Test.test_function1")

    def testfunction2(self):
        print("in Class3Test.testfunction2")

    def function3_test(self):
        print("in Class3Test.function3_test")

    def function4test(self):
        print("in Class3Test.function4test")

首先上述文件中通过与标准测试发现规则对比可以很容易的分析出只有 ex_03_test.py和test_ex_01.py符合文件命名规则要求,其他两个文件中的测试函数或者测试类不会被pytest发现

每个文件中的代码分析见代码中的每个函数或者类上面的分析

下面在pycharm的terminal中首先进入到ex_003的目录,然后执行如下命令:

pytest -s

运行输出结果如下:

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\ex_003>pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\ex_003
plugins: html-2.1.1, metadata-1.10.0
collected 8 items                                                                                                                                                       

ex_03_test.py in test_function1
.in testfunction2
.in TestClass1.test_function1
.in TestClass1.testfunction2
.
test_ex_01.py in test_function1
.in testfunction2
.in TestClass1.test_function1
.in TestClass1.testfunction2
.

=========================================================================== warnings summary ===========================================================================
ex_03_test.py:38
  G:\lamb_source\pytest_example_for_full_documentation\ex_003\ex_03_test.py:38: PytestCollectionWarning: cannot collect test class 'TestClass2' because it has a __init__
 constructor (from: ex_03_test.py)
    class TestClass2():

test_ex_01.py:44
  G:\lamb_source\pytest_example_for_full_documentation\ex_003\test_ex_01.py:44: PytestCollectionWarning: cannot collect test class 'TestClass2' because it has a __init__
 constructor (from: test_ex_01.py)
    class TestClass2():

-- Docs: https://docs.pytest.org/en/latest/warnings.html
==================================================================== 8 passed, 2 warnings in 0.16s =====================================================================

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\ex_003>

2 pytest 在python文件中的用例组织形式

主要组成部分有setup,teardown 和各个用例,每个用例的方法名必须以test开头,在每个用例执行之前会去执行setup初始化配置,每个用例执行完成之后都会去执行teardown清理配置

在test_example.py文件中编写如下测试代码:

def setup():
    print("in setup")
    
def teardown():
    print("in teardown")
    
def test_func1():
    print("in test_func1")
    
def test_func2():
    print("in test_func2")
    
def test_func3():
    print("in test_func3")

然后在pycharm的terminal中首先切换到test_example.py的目录中,然后执行如下命令:

pytest -s

运行结果如下所示,即每个测试用例在执行之前首先执行setup操作,每个用例执行完成之后都执行了teardown操作

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py in setup
in test_func1
.in teardown
in setup
in test_func2
.in teardown
in setup
in test_func3
.in teardown

========================================================================== 3 passed in 0.08s ===========================================================================

3 使用类组织测试用例

使用文件组织用例的时候,如果想在所有用例之前只执行一次初始化操作,而当所有用例执行完成之后再进行公共的清理配置操作,在文件组织用例的形式下是做不到的,这个时候就需要使用测试类来组织用例

在使用类组织用例的时候,类名必须是Test开头,类不能有初始化函数__init__,类中的测试用例名称同样必须test开头,此外,类中可以有setup和teardown,setup是在类中每个用例执行之前执行,teardown是在每个用例执行结束之后执行

除此以外,类中还有setup_class和teardown_class,setup_class是在类的所有用例执行前执行一次,待所有用例执行结束之后,再执行testdown_class方法

在test_example.py文件中编写如下测试代码

class TestFunction(object):
    def setup_class(self):
        print("\nin setup_class")

    def teardown_class(self):
        print("in teardown_class")

    def setup(self):
        print("in setup")

    def teardown(self):
        print("in teardown")

    def test_func1(self):
        print("in test_func1")

    def test_func2(self):
        print("in test_func2")

    def test_func3(self):
        print("in test_func3")

在pycharm的terminal中切换至ex_006的目录中,然后执行如下命令

pytest -s

运行结果如下:

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py
in setup_class
in setup
in test_func1
.in teardown
in setup
in test_func2
.in teardown
in setup
in test_func3
.in teardown
in teardown_class

========================================================================== 3 passed in 0.06s ===========================================================================

4 pytest用例的执行方式

  • (1) 在一个目录下执行pytest,会递归查找当前目录下的所有符合用例发现规则的所有用例,然后全部执行

如当前目录下有两个py文件分别为:test_example.py,test_example2.py,两个文件中的代码均为如下:

class TestFunction(object):
    def setup_class(self):
        print("\nin setup_class")

    def teardown_class(self):
        print("in teardown_class")

    def setup(self):
        print("in setup")

    def teardown(self):
        print("in teardown")

    def test_func1(self):
        print("in test_func1")

    def test_func2(self):
        print("in test_func2")

    def test_func3(self):
        print("in test_func3")

在当前目录下执行 pytest,结果如下:

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 6 items                                                                                                                                                       

test_example.py ...                                                                                                                                               [ 50%]
test_example2.py ...                                                                                                                                              [100%]
========================================================================== 6 passed in 0.06s ===========================================================================
  • (2) 可以指定文件,比如 pytest test_example.py 即执行test_example.py文件中的所有符合用例发现规则的脚本
(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest test_example.py
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py ...                                                                                                                                               [100%]

========================================================================== 3 passed in 0.03s ===========================================================================
  • (3) 可以指定文件中的某个具体测试类,如:pytest test_example.py::TestFunction
    执行结果如下:
(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest test_example.py::TestFunction
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py ...                                                                                                                                               [100%]

========================================================================== 3 passed in 0.02s ===========================================================================
  • (4) 还可以指定具体文件中的具体类中的具体某一个测试用例,如:pytest test_example.py::TestFunction::test_func1
    运行结果如下:
(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest test_example.py::TestFunction::test_func1
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 1 item                                                                                                                                                        

test_example.py .                                                                                                                                                 [100%]

========================================================================== 1 passed in 0.02s ===========================================================================
  • (5) pytest -s 详细打印
(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest test_example.py::TestFunction::test_func1
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 1 item                                                                                                                                                        

test_example.py .                                                                                                                                                 [100%]

========================================================================== 1 passed in 0.02s ===========================================================================

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest -s test_example.py
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py
in setup_class
in setup
in test_func1
.in teardown
in setup
in test_func2
.in teardown
in setup
in test_func3
.in teardown
in teardown_class

========================================================================== 3 passed in 0.02s ===========================================================================
  • (6) pytest -m xxx 可以指定了打了xxx标记的用例执行,具体打标记的操作后续会讲,这里主要演示执行

在test_example.py中编写如下代码:

import pytest
class TestFunction(object):
    def setup_class(self):
        print("\nin setup_class")

    def teardown_class(self):
        print("in teardown_class")

    def setup(self):
        print("in setup")

    def teardown(self):
        print("in teardown")
    @pytest.mark.test
    def test_func1(self):
        print("in test_func1")

    def test_func2(self):
        print("in test_func2")

    def test_func3(self):
        print("in test_func3")

使用下面命令执行发现只执行了一个用例,因为此用例打了test的标签

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest -s -m test
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items / 2 deselected / 1 selected                                                                                                                           

test_example.py
in setup_class
in setup
in test_func1
.in teardown
in teardown_class


=========================================================================== warnings summary ===========================================================================
test_example.py:14
  G:\lamb_source\pytest_example_for_full_documentation\test_demo\test_example.py:14: PytestUnknownMarkWarning: Unknown pytest.mark.test - is this a typo?  You can regist
er custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
    @pytest.mark.test

-- Docs: https://docs.pytest.org/en/latest/warnings.html
============================================================== 1 passed, 2 deselected, 1 warning in 0.07s ==============================================================
  • (7) pytest -x 遇到错误等及不再继续执行

在test_example.py中编写如下代码:有三个用例,其中第二个会出现断言错误

import pytest
class TestFunction(object):
    def setup_class(self):
        print("\nin setup_class")

    def teardown_class(self):
        print("in teardown_class")

    def setup(self):
        print("in setup")

    def teardown(self):
        print("in teardown")

    def test_func1(self):
        print("in test_func1")

    def test_func2(self):
        print("in test_func2")
        assert 1==2

    def test_func3(self):
        print("in test_func3")

分别用pytest 和pytest -x 执行,结果如下:当使用-x参数时结果为一个通过一个失败,只执行了两个,而使用pytest时,三个用例都执行了

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py .F.                                                                                                                                               [100%]

=============================================================================== FAILURES ===============================================================================
_______________________________________________________________________ TestFunction.test_func2 ________________________________________________________________________

self = 

    def test_func2(self):
        print("in test_func2")
>       assert 1==2
E       assert 1 == 2

test_example.py:20: AssertionError
------------------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------------------
in setup
------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------
in test_func2
----------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------
in teardown
======================================================================= short test summary info ========================================================================
FAILED test_example.py::TestFunction::test_func2 - assert 1 == 2
===================================================================== 1 failed, 2 passed in 0.14s ======================================================================

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest -x
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py .Fin teardown_class


=============================================================================== FAILURES ===============================================================================
_______________________________________________________________________ TestFunction.test_func2 ________________________________________________________________________

self = 

    def test_func2(self):
        print("in test_func2")
>       assert 1==2
E       assert 1 == 2

test_example.py:20: AssertionError
------------------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------------------
in setup
------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------
in test_func2
----------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------
in teardown
======================================================================= short test summary info ========================================================================
FAILED test_example.py::TestFunction::test_func2 - assert 1 == 2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
===================================================================== 1 failed, 1 passed in 0.14s ======================================================================

  • (8) pytest --maxfail=num 可以控制在num个用例失败后停止执行

下面使用(7)中的测试代码,执行下面命令,只执行了两个用例,因为达到了最大失败用例1个,即停止执行

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>pytest --maxfail=1
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: G:\lamb_source\pytest_example_for_full_documentation\test_demo
plugins: html-2.1.1, metadata-1.10.0
collected 3 items                                                                                                                                                       

test_example.py .Fin teardown_class


=============================================================================== FAILURES ===============================================================================
_______________________________________________________________________ TestFunction.test_func2 ________________________________________________________________________

self = 

    def test_func2(self):
        print("in test_func2")
>       assert 1==2
E       assert 1 == 2

test_example.py:20: AssertionError
------------------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------------------
in setup
------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------
in test_func2
----------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------
in teardown
======================================================================= short test summary info ========================================================================
FAILED test_example.py::TestFunction::test_func2 - assert 1 == 2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
===================================================================== 1 failed, 1 passed in 0.14s ======================================================================

(PytestEnv) G:\lamb_source\pytest_example_for_full_documentation\test_demo>

原文链接

你可能感兴趣的:(Pytest专题,python)