一、命令行指定目录
指定目录时,只执行指定目录的用例,目录命名没有具体要求
文件目录结构如下:
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 =====================================================================
$