Pytest----默认用例发现规

简介: Pytest----默认用例发现规

一、命令行指定目录

指定目录时,只执行指定目录的用例,目录命名没有具体要求

文件目录结构如下:

tests
  |--------demo01
             |--------__init__.py
             |--------test_demo01.py
  |--------demo02
             |--------__init__.py
             |--------test_demo02.py

test_demo01.py文件内容:

def test_func1():
    print("in test_func1......")
    assert 1==1

test_demo02.py文件内容

def test_func2():
    print("in test_func2......")
    assert 1==1

如下,在tests目录下指定demo01目录,只会执行demo01目录下的测试用例

$ pytest -s demo01
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: D:\src\blog\tests
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 1 item                                                                                                                                                        

demo01\test_demo01.py in test_func1......
.

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

二、命令行不指定目录

命令行不指定目录时,会查找当前目录下的测试用例以及递归的查找当前目录下得文件夹

目录结构如下

tests
  |--------test_demo.py
  |--------demo01
             |--------__init__.py
             |--------test_demo01.py
             |--------demo01_01
                          |--------__init__.py
                          |--------test_demo01_01.py
  |--------demo02
             |--------__init__.py
             |--------test_demo02.py

test_demo.py,test_demo01.py,test_demo02.py,test_demo01_01.py内容如下:

def test_func():
    print("in test_func......")
    assert 1==1

在tests目录下执行pytest -s,不指定目录,如下:

$ pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: D:\src\blog\tests
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 4 items                                                                                                                                                       

test_demo.py in test_func......
.
demo01\test_demo01.py in test_func......
.
demo01\demo01_01\test_demo01_01.py in test_func......
.
demo02\test_demo02.py in test_func......
.

========================================================================== 4 passed in 0.05s ===========================================================================
$

三、测试脚本文件名默认规则

测试脚本文件名规则要求test_.py 或者 _test.py格式的

目录结构如下:

demo01
  |--------__init__.py
  |--------test_demo01.py
  |--------demo02.py
  |--------demo03_test.py
  |--------demo04test.py
  |--------testdemo05.py

其中上述除__init__.py文件以外,其他文件的内容均为如下:

def test_func():
    print("in test_func...")
    assert 1==1

使用pytest -s 执行结果如下,可以发现这里只执行了test_demo01.py和demo03_test.py 两个文件中的测试脚本,其他文件中的测试脚本并没有执行,原因就是文件的命名不符合pytest默认的文件命名规则

$ pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: G:\src\blog\tests\demo01
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 2 items                                                                                                                                                       

demo03_test.py in test_func...
.
test_demo01.py in test_func...
.

========================================================================== 2 passed in 0.07s ===========================================================================
$ 

四、不同目录下测试文件命名是否可以相同

当每个目录下都有__init__.py文件的时候,不同目录下的测试文件命名是完全可以相同的,这也是推荐的做法,但是当目录中没有__init__.py文件的时候,就需要注意了,如果出现文件重名的,可能会出现问题了,先来看下下面的结果

目录结构如下:

demo01
  |--------demo02
             |--------__init__.py
             |--------test_demo01.py
  |--------test_demo01.py

test_demo01.py文件中的内容均为如下内容:

def test_func():
    print("in test_func...")
    assert 1==1

在demo01的目录下执行pytest -s ,结果如下,可以看出,这里两个文件名相同的,因为demo02文件夹中有__init__.py文件,所有此时是可以执行的

$ pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: G:\src\blog\tests\demo01
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 2 items                                                                                                                                                       

test_demo01.py in test_func...
.
demo02\test_demo01.py in test_func...
.

========================================================================== 2 passed in 0.06s ===========================================================================
$

此时将demo02目录中的__init__.py文件删除,然后再执行 pytest -s,结果如下,可以看出此时报错了

$ pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: G:\src\blog\tests\demo01
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 1 item / 1 error                                                                                                                                              

================================================================================ ERRORS ================================================================================
________________________________________________________________ ERROR collecting demo02/test_demo01.py ________________________________________________________________
import file mismatch:
imported module 'test_demo01' has this __file__ attribute:
  G:\src\blog\tests\demo01\test_demo01.py
which is not the same as the test file we want to collect:
  G:\src\blog\tests\demo01\demo02\test_demo01.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
======================================================================= short test summary info ========================================================================
ERROR demo02/test_demo01.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=========================================================================== 1 error in 0.15s ===========================================================================
$

这里是跟pytest加载用例的原理有关,pytest在加载用例的时候实质是把测试用例文件当做模块导入的,而在导入模块之前,pytest首先是把一个basedir的变量添加到环境变量中,basedir的计算原理是针对每个测试脚本,向上递归的查找,找到最顶层带有__init__.py文件的目录,然后这个目录的上层目录作为basedir添加到环境变量中,然后根据basedir计算每个测试脚本文件的相对路径,这么说比较枯燥,以下面的目录结构为例:

针对第一个test_demo01.py文件,从当前目录开上往上找,找到最后一层带有__init__.py文件的目录,这里是demo04,此时pytest会把demo04的上一层目录demo03添加到环境变量中,然后从demo03开始确定第一个test_demo01.py的导入的相对路径,即demo04.test_demo01.py

针对第二个test_demo01.py文件,同样从当前目录开始往上找,找到最后一层带有__init__.py文件的目录,这里也是demo04,此时pytest会把这个目录的上一层目录demo02添加到环境变量中,然后从demo02开始计算第二个test_demo01.py的导入的相对路径,即demo04.test_demo01.py

即此时发现这两个相同名字的文件虽然在不同层次不同文件夹中,但是经过pytest计算发现他们两个的导入路径完全相同,因此此时就会报错

demo02
  |--------demo03
             |--------demo04
                        |--------__init__.py
                        |--------test_demo01.py
  |--------demo04
             |--------__init__.py
             |--------test_demo01.py

在demo02目录下执行 pytest -s 命令得到如下结果,与上述分析结果一致,即报错了

$ pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: G:\src\blog\tests\demo02
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 1 item / 1 error                                                                                                                                              

================================================================================ ERRORS ================================================================================
________________________________________________________________ ERROR collecting demo04/test_demo01.py ________________________________________________________________
import file mismatch:
imported module 'demo04.test_demo01' has this __file__ attribute:
  G:\src\blog\tests\demo02\demo03\demo04\test_demo01.py
which is not the same as the test file we want to collect:
  G:\src\blog\tests\demo02\demo04\test_demo01.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
======================================================================= short test summary info ========================================================================
ERROR demo04/test_demo01.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=========================================================================== 1 error in 0.20s ===========================================================================

$

因此当目录中不带有__init__.py文件的时候,如果再使用相同文件名的测试脚本,则是有可能会报错的,具体会不会报错就需要根据上面的导入模块原理去分析

因此为了免去分析以及引起不必要的麻烦,这里强烈推荐创建脚本的时候每个目录都存放一个__init__.py文件,这样是无论如何也不会出现两个相同的相对导入路径的,这个也是为什么在有一些文章或教程中直接宣称创建pytest用例的时候必须要带__init__.py文件的原因

更多关于模块导入的内容,请参考 Pytest(二十五)测试脚本的加载原理

五、测试脚本中测试函数命名规则

测试脚本中测试函数命名以test开头的函数即作为测试函数

test_demo01.py内容如下:

def test_func():
    print("in test_func...")
    assert 1==1

def testfunc():
    print("in testfunc...")
    assert 1==1

def func_test():
    print("in func_test...")
    assert 1==1

def Test_func():
    print("in Test_func...")
    assert 1==1

使用pytest -s 执行结果如下,可以发现这里test_func和testfun均作为测试函数被执行

$  pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: G:\src\blog\tests\demo01
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 2 items                                                                                                                                                       

test_demo01.py in test_func...
.in testfunc...
.

========================================================================== 2 passed in 0.05s ===========================================================================

$

六、测试脚本中测试类命名规则

测试类命名要求以Test开头,并且测试类中不能有__init__函数,测试类中的方法同样要求以test开头

test_demo01.py文件内容如下:

class TestDemo01():
    def __init__(self):
        pass

    def test_func(self):
        assert 1==1

class testDemo01():
    def test_func(self):
        assert 1 == 1

class DemoTest():
    def test_func(self):
        assert 1 == 1

class TestDemo02():
    def test_func(self):
        assert 1 == 1

    def testfunc(self):
        assert 1 == 1

    def func_test(self):
        assert 1==1

执行结果如下,可以发现只有TestDemo02类中的test_func和testfunc方法作为测试函数被识别到,其他的均不符合要求

$ pytest -v
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\python39\python.exe
cachedir: .pytest_cache
rootdir: G:\src\blog\tests\demo01
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 2 items                                                                                                                                                       

test_demo01.py::TestDemo02::test_func PASSED                                                                                                                      [ 50%]
test_demo01.py::TestDemo02::testfunc PASSED                                                                                                                       [100%]

=========================================================================== warnings summary ===========================================================================
test_demo01.py:1
  G:\src\blog\tests\demo01\test_demo01.py:1: PytestCollectionWarning: cannot collect test class 'TestDemo01' because it has a __init__ constructor (from: test_demo01.py)

    class TestDemo01():

-- Docs: https://docs.pytest.org/en/stable/warnings.html
===================================================================== 2 passed, 1 warning in 0.03s =====================================================================

$
目录
相关文章
|
测试技术
30-pytest-重复执行用例-pytest-repeat
30-pytest-重复执行用例-pytest-repeat
30-pytest-重复执行用例-pytest-repeat
|
测试技术 Python
pytest--运行指定的测试和参数化
pytest--运行指定的测试和参数化
|
测试技术 Python
02-pytest-用例运行规则
02-pytest-用例运行规则
|
测试技术
15-pytest-自定义用例执行顺序
15-pytest-自定义用例执行顺序
|
测试技术 C++
pytest pytest.ini配置 用例分组 用例跳过
pytest pytest.ini配置 用例分组 用例跳过
|
测试技术
pytest学习和使用14-Pytest用例执行结果有哪几种状态?
pytest学习和使用14-Pytest用例执行结果有哪几种状态?
91 0
|
测试技术
Pytest----pytest.ini自定义测试文件、测试用例、测试类命名规则
Pytest----pytest.ini自定义测试文件、测试用例、测试类命名规则
319 0
Pytest----pytest.ini自定义测试文件、测试用例、测试类命名规则
|
测试技术
Pytest----如何管理日志
Pytest----如何管理日志
688 0
|
开发工具
Pytest----生成allure执行报告
Pytest----生成allure执行报告
265 0
Pytest----生成allure执行报告
|
测试技术 Python
Pytest系列(13)- 重复执行用例插件之pytest-repeat的详细使用
Pytest系列(13)- 重复执行用例插件之pytest-repeat的详细使用
269 0
Pytest系列(13)- 重复执行用例插件之pytest-repeat的详细使用