pytest發(fā)現(xiàn)規(guī)則
- 如果沒指定參數(shù),并且配置了 testpaths (詳見1.testpaths),會從 testpaths 查找,否則從當前目錄查找。也可以通過命令行指定目錄,文件名,節(jié)點 id 的組合。
- 遞歸目錄,直到遇到
norecursedirs
(詳見3.norecursedirs)為止 - 在所有目錄中搜索
test_*.py
或者*_test.py
文件,并通過測試包名(詳見4. 測試包名)導(dǎo)入他們。 - 從文件中收集測試項,包括:
-
test
開頭的函數(shù)或類外方法 -
test
開頭的函數(shù)或方法,在Test
開頭的類中(這個類不能有 init方法)
-
1.testpaths
從 rootdir 下的 testpaths 開始找 test(如果命令行沒設(shè)置其他的目錄,文件,或測試ids) ,它可以加速測試收集,過濾掉不想要的測試內(nèi)容。
創(chuàng)建如下目錄結(jié)構(gòu),在 tox.ini 文件中加入 testpaths :
tox.ini 配置文件如下:
[pytest]
testpaths = a/a1
可以看到, pytest 設(shè)置 tox.ini 文件為 inifile ,同時設(shè)置了 testpaths ,并且只從 a/a1 目錄下收集測試項:
[image1701×419 15.2 KB](https://ceshiren.com/uploads/default/original/2X/2/2e3c3ed384523af8f4cc67f8e510e1f0158b5090.png)
2.rootdir
rootdir 的作用如下:
- 構(gòu)建
nodeids
時,每一個 test 都有唯一的標識 nodeid ,標識的根目錄就是rootdir
,包括絕對路徑,類名, 函數(shù)名和參數(shù)化。 - 存放插件的測試信息,比如 cache 1 插件在
rootdir
下創(chuàng)建了.pytest_cache
目錄存儲交叉測試運行狀態(tài)。
比如當 rootdir 為 pytest_example 時,其下就存在 cache 插件存放目錄 .pytest_cache :
可以用命令行參數(shù)或者 ini_file
指定 `rootdir :
-
--rootdir=path
可以設(shè)置 rootdir 目錄 - 用
pytest.ini
中的 addopts 參數(shù)可以修改 pytest 默認參數(shù)
pytest.ini 內(nèi)容如下,它指定 pytest 命令的默認參數(shù)為 --rootdir=path
,當只執(zhí)行 pytest
命令時,會自動加上 --rootdir=path
:
# content of pytest.ini or tox.ini
[pytest]
addopts = --rootdir=path
如果不顯示指定 rootdir 的位置, pytest 會按照下述規(guī)則自動尋找 rootdir :
- 尋找多個參數(shù)的共同祖先目錄,如果沒有,將當前工作目錄設(shè)置為共同祖先目錄。
- 從共同祖先目錄及上級目錄中找三個文件
pytest.ini
,tox.ini
和setup.cfg
,若找到其中任何一個文件,則將其變?yōu)?ini-file
,而它所在的目錄就是rootdir
。 - 如果沒有
ini-file
,從共同祖先目錄及上級目錄中找setup.py
,如果有,則將其所在目錄設(shè)為rootdir
。 - 如果沒有
setup.py
,從每個參數(shù)及其上級目錄中找pytest.ini
,tox.ini
和setup.cfg
, 如果找到,它將成為 ini-file ,并且其目錄將成為rootdir。 - 如果沒有 ini-file ,把共同祖先目錄作為 rootdir,這么做的原因是,即使不是包,且沒有配置文件,也能使用 pytest 。
比如以下目錄,請注意其中的 pytest.ini 文件位置:
運行如下 pytest 命令, pytest 首先找到兩個參數(shù)的公共祖先目錄 a ,然后從 a 目錄中找到了 pytest.ini 文件,于是這個文件就是 inifile ,而 rootdir 就是目錄 a :
[image1132×219 28.7 KB](https://ceshiren.com/uploads/default/original/2X/b/b3662a7dca7c51c8501690cf9bb8b9406abb0713.png)
將 pytest.ini 的位置放入 a1目錄下:
pytest 首先找到了公共目錄 a ,但是在目錄 a 及其上級目錄沒有發(fā)現(xiàn)任何配置文件(pytest.ini , tox.ini 和 setup.cfg,setup.py),于是從每個參數(shù)及其上級目錄中找,發(fā)現(xiàn)目錄 a1 下存在 pytest.ini ,它將成為 ini-file ,并且其目錄將成為rootdir。
[image1166×217 27.9 KB](https://ceshiren.com/uploads/default/original/2X/8/8459740ccc0d34bfe8070cae9b2778f73f76580f.png)
沒有 pytest.ini 文件時, rootdir 是 pytest_example 而不是 a , 比如下圖
image1173×217 28.3 KB](https://ceshiren.com/uploads/default/original/2X/6/6ca3274a41472879e58ed16abc2cfcbc0d47f143.png)
如果沒有參數(shù), pytest 會把當前目錄設(shè)為 rootdir
。比如參考以下目錄結(jié)構(gòu)和運行結(jié)果:
image1005×226 27.1 KB](https://ceshiren.com/uploads/default/original/2X/e/efd3d98414f2721188f69650bc5e61780e5a103a.png)
即使設(shè)置了 pytest.ini ,如果 pytest 沒有參數(shù)的話,會把當前目錄 a 設(shè)置為 rootdir :
image917×227 26.5 KB](https://ceshiren.com/uploads/default/original/2X/1/1ec2c9a6148d55a5d2f733b3f99e26f05e97cb86.png)
注意:只要存在 pytest.ini
文件,就能被 pytest 匹配上,但是 tox.ini
和 setup.cfg
必須包含 [pytest]
或者 [tool:pytest]
部分才能被匹配,如果有多個 ini-file ,最終只會挑選出一個(優(yōu)先選擇pytest.ini
)。 pytest 存在一個 bug ,用戶可以自定義插件,插件可以傳參,如果傳入的是路徑,比如 pytest --log-output ../../test.log args
,上述插件不寫 args 的話, pytest 會使用 test.log 文件夾確定rootdir(參見issue 1435),比如 pytest --log-output ../../test.log
。即使用點 .
來引用當前工作目錄,也會發(fā)生上述問題。
3.配置 norecursedirs
https://docs.pytest.org/en/latest/reference.html#confval-norecursedirs 1
設(shè)置目錄的基本名字表達式(fnmatch-match風(fēng)格),用于是否進行遞歸。
* 匹配所有內(nèi)容
? 匹配所有單字符
[seq] 匹配 seq 中的任一個字符
[!seq] 匹配不在 seq 中的字符
默認表達式有 :
'.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg', 'venv'
,可以設(shè)置norecursedirs
替代默認表達式,比如不遞歸指定目錄:
[pytest]
norecursedirs = .svn _build tmp*
pytest
會通過 activation 腳本識別并忽略 python 虛擬環(huán)境, pytest 不會收集虛擬環(huán)境中的 test ,但可以使用 ??collect?in?virtualenv
選項開啟收集。注意,norecursedirs
級別高于 ??collect?in?virtualenv
,比如你開啟了 ??collect?in?virtualenv
選項,就必須重寫 norecursedirs
才能讓其生效(因為默認值有 venv 會過濾掉虛擬環(huán)境)。
比如下面的目錄結(jié)構(gòu),在 pytest_example 目錄下存在配置文件 tox.ini :
tox.ini 的內(nèi)容如下:
[pytest]
norecursedirs = a1
[image1510×406 14.2 KB](https://ceshiren.com/uploads/default/original/2X/5/5f8afaa0b020e9010b4a4147d9a2d99f41e6220a.png)
4. 測試包名
如果 pytest
發(fā)現(xiàn)一個測試文件 a/b/test_module.py
,會發(fā)生以下情況:
- 設(shè)置
basedir
:發(fā)現(xiàn)第一個不包含__init__.py
的上級目錄,如果a
和b
都包含__init__.py
文件,a
的父目錄將成為basedir
。 - 使用
sys.path.insert(0, basedir)
將 basedir 置于環(huán)境變量的首位。 -
import a.b.test_module
把路徑分割符\
轉(zhuǎn)換成了 “.” ,讓目錄名和文件名直接映射到導(dǎo)入名。
在較大的項目中,可能會相互導(dǎo)入多個測試模塊,規(guī)范的導(dǎo)入名稱可規(guī)避意外情況,例如一個測試模塊被導(dǎo)入兩次。
測試
1. 無參數(shù)
現(xiàn)在不對 pytest 設(shè)置額外參數(shù),不設(shè)置 testpaths ,也不設(shè)置 norecursedirs 。假設(shè)以下目錄結(jié)構(gòu),在目錄 pytest_example 下有一個包 a ,它下面 存在一個 test_a.py 和目錄 a1 ,目錄 a1 下面存在 test_a2.py:
pytest_example/
|- a/
|- __init__.py
|- test_a.py
|- a1/
|- tests/
|- test_a1.py
test_a.py 和 test_a1.py 的代碼和執(zhí)行結(jié)果分別如下:
# 以下是 test_a.py 代碼
def test_a():
print('test_a')
# 以下是 test_a2.py 代碼
class Test_A1:
def test_a1(self):
print("test_a1")
使用命令行 cd 到 pytest_example 目錄下,執(zhí)行 pytest
命令,其結(jié)果如下:
image995×273 30.2 KB](https://ceshiren.com/uploads/default/original/2X/4/42e0d5faa63967a83976d8e8e9d1a8334ccc5aa7.png)
可以看出, pytest 從 pytest_example 目錄開始遞歸收集測試,收集到了兩個測試內(nèi)容: test_a.py 和 test_a1.py,它不會區(qū)分包和目錄,也不會捕獲標準輸出, 輸出結(jié)果打印 rootdir 的內(nèi)容 ,后面會講它的作用。
更多技術(shù)文章可點擊獲取 http://qrcode.testing-studio.com/f?from=jianshu&url=https://ceshiren.com/t/topic/3822