第一章 pytest入門
常用啟動(dòng)命令
1.pytest會(huì)在當(dāng)前目錄及子目錄尋找測(cè)試用例
2.Task結(jié)構(gòu),用于UI層和API層之間傳遞信息:
from collections import namedtuple
Task = namedtuple('Task',['summary','owner','done','id'])
# __new__.__defaults__創(chuàng)建默認(rèn)Task對(duì)象鼻听,不必指定所有屬性
Task.__new__.__defaults__ = (None,None,False,None)
def test_defaluts():
t1=Task() # 默認(rèn)值
t2=Task(None,None,False,None)
assert T1 == T2
# 演示使用屬性名(而不是索引)來(lái)訪問(wèn)對(duì)象成員
def test_member_access():
t=Task('buy milke','brain')
assert t.summary == 'buy milke'
assert t.owner == 'brain'
assert (t.done,t.id) == (False,None)
# `_asdict` 和 `_replace`函數(shù)
3.運(yùn)行單個(gè)測(cè)試用例: pytest -v test.py::test_asdict
4.常用命令行
--collect-only
: 只是展示給定配置下運(yùn)行哪些測(cè)試用例瘪松,方便檢查
-k
: 允許使用表達(dá)式指定運(yùn)行測(cè)試方法
pytest -k "asdict or defaluts" --collect-only
pytest -k "asdict or defaluts"
pytest -v -k "asdict or defaluts"
-m
運(yùn)行指定標(biāo)記的用例
-m "mark1 and mark2"
同時(shí)標(biāo)記mark1和mark2的
-m "mark1 or mark2"
標(biāo)記mark1或mark2的
-m "mark1 and not mark2"
標(biāo)記mark1,過(guò)濾掉mark2的
-x
遇到失敗停止pytest運(yùn)行
--maxfail=num
指定失敗幾次,停止運(yùn)行 。num=1時(shí)同-x (指運(yùn)行所有指定測(cè)試用例時(shí),失敗N次后停止)
-s 與 --capture=method
打印符合標(biāo)準(zhǔn)的輸出或信息酿联,如print
-l /--showlocals
測(cè)試失敗時(shí)打印出局部變量名和值,可避免一些不必要的print
-v
或者 --verbose
: 可以查看具體運(yùn)行詳情
-q/--quiet
:與-v
相反夺巩,簡(jiǎn)化輸出信息贞让,常和--tb=line
(僅打印異常的代碼位置)搭配使用
--tb=style
決定失敗時(shí)輸出信息的顯示方式 (short,line柳譬,no:關(guān)閉,lang等)
第二章 編寫測(cè)試函數(shù)
演示如何使用assert喳张,如何處理可預(yù)期和不可預(yù)期的異常,如果借助類美澳,模塊销部,目錄來(lái)組織測(cè)試,以便管理大量的測(cè)試制跟。使用mark為預(yù)期會(huì)失敗的測(cè)試做標(biāo)記
測(cè)試示例程序
- test/func/init.py和test/unit/init.py都是空文件舅桩,作用是給pytest提供搜索路徑,找到測(cè)試根目錄和
pytest.ini
文件雨膨。(conftest.py也可以統(tǒng)一放在test根目錄) -
pytest.ini
是可選的擂涛,它保存了pytest在該項(xiàng)目下的特定配置。 -
conftest.py
是pytest的“本地插件庫(kù)”聊记,包含hook函數(shù)和fixture歼指。hook可以將自定義邏輯引入pytest,用于改善pytest的執(zhí)行流程甥雕,fixture則是用于測(cè)試前后執(zhí)行配置及銷毀邏輯的外殼函數(shù),可以傳遞測(cè)試中用到的資源胀茵。 - 測(cè)試demo下載 傳送門
安裝cd code/tasks_proj pip install .
使用assert
- pytest.org上有很多復(fù)雜的assert例子
- 預(yù)期異常
with pytest.raises(TypeError):
task.add(task='not a task object')
# 無(wú)論with內(nèi)容是什么社露,都會(huì)發(fā)生TypeError異常。如果測(cè)試通過(guò)琼娘,說(shuō)明發(fā)生了預(yù)期的TypeError異常峭弟;如果拋出其他類型的異常,則與預(yù)期不一致脱拼,測(cè)試失敗瞒瘸。
with pytest.raises(ValueError) as excinfo:
tasks.start_task_db('some','mysql')
exception_msg=excinfo.value.args[0]
assert exception_msg == "db_type must be a 'tiny' or 'mongo'"
# 不止校驗(yàn)異常類型,還可以校驗(yàn)異常消息
標(biāo)記測(cè)試
-
@pytest.mark.skip()
裝飾器 : 跳過(guò)測(cè)試 (skipif
可設(shè)置跳過(guò)條件) -
@pytest.mark.xfail()
:告訴pytest運(yùn)行此測(cè)試熄浓,但我們預(yù)期會(huì)失斍槌簟(如果實(shí)際失敗,則記過(guò)為xfail,如果實(shí)際成功俯在,則結(jié)果為XPASS竟秫,可在pytest.ini中強(qiáng)制執(zhí)行結(jié)果為fail
[pytest]
xfail_strict=ture
參數(shù)化
1.@pytest.mark.parametrize()
第一個(gè)參數(shù)為逗號(hào)分隔的字符串列表,第二個(gè)參數(shù)是值列表parametrize()
2.parametrize()在測(cè)試運(yùn)行會(huì)優(yōu)化測(cè)試用例可視化跷乐,也可引入額外自定義參數(shù)肥败。ids
:標(biāo)識(shí)用例的id
@pytest.mark.parametrize('a,b', [['2', '3'], ['1', '4']], ids=['2和3', '1和4'])
def test_param(a, b):
print("===", int(a))
assert int(a) + int(b) == 5
3.parametrize()可以加在測(cè)試類
上,這樣數(shù)據(jù)集會(huì)被傳遞給所有類方法
4.parametrize()可以在參數(shù)值旁定義id做標(biāo)識(shí)愕提,pytest.param(<value>馒稍,id='something')
在id不能被參數(shù)化批量生成時(shí),需要自定義時(shí)浅侨,很管用
param = [
pytest.param(1, 2, 5, id='failed'),
pytest.param(3, 4, 7, id='success')]
@pytest.mark.parametrize('a,b,expect', param)
def test_param2(a, b, expect):
assert int(a) + int(b) == int(expect)
第三章 pytest fixture
安裝tasks纽谒,cd code;pip install ./tasks_proj/
1.fixture
函數(shù)會(huì)在測(cè)試函數(shù)之前運(yùn)行,如果fixture函數(shù)包含yield仗颈,那么系統(tǒng)會(huì)在yield
處停止佛舱,轉(zhuǎn)而運(yùn)行測(cè)試函數(shù),等測(cè)試函數(shù)運(yùn)行完再回到fixture挨决,運(yùn)行yield后的代碼
2.--setup-show
回溯fixture的執(zhí)行過(guò)程
3.fixture內(nèi)發(fā)生的assert異常結(jié)果為ERROR
请祖,測(cè)試函數(shù)assert發(fā)生的異常結(jié)果為FAIL
4.usefixtures
5.autouse=True
作用域內(nèi)的函數(shù)都運(yùn)行該fixture
fixture作用范圍scope
:
function
fixture默認(rèn)值,每個(gè)測(cè)試函數(shù)運(yùn)行一次脖祈,配置代碼再測(cè)試用例運(yùn)行之前運(yùn)行肆捕,銷毀代碼再測(cè)試用例運(yùn)行之后運(yùn)行
class
每個(gè)測(cè)試類運(yùn)行一次,無(wú)論測(cè)試類里有多少類方法都可以共享這個(gè)fixture
module
每個(gè)模塊只需要運(yùn)行一次盖高,無(wú)論模塊里有多少個(gè)測(cè)試函數(shù)慎陵,類方法或其他fixture都可以共享這個(gè)fixture
session
每次會(huì)話只需要運(yùn)行一次,一次pytest會(huì)話中的所有測(cè)試函數(shù)喻奥,方法都可以共享這個(gè)fixture
--setup-show 可以觀察每個(gè)fixture被調(diào)用的次數(shù)席纽,以及在各自作用范圍下執(zhí)行配置,銷毀邏輯的順序
fixture只能使用同級(jí)別的或者更高級(jí)別的fixture撞蚕,不能反過(guò)來(lái)
fixture參數(shù)化
@pytest.fixture(params=tasks润梯,ids=task_ids) #也可參數(shù)化,也可指定id
def a_task(request): # request是pytest內(nèi)建的fixture之一甥厦,代表fixture的調(diào)用狀態(tài)纺铭,有一個(gè)param字段,會(huì)被params列表的一個(gè)元素填充
return request.param
2.fixture_value
內(nèi)置fixture刀疙?
- 對(duì)測(cè)試函數(shù)進(jìn)行參數(shù)化處理舶赔,可以多次運(yùn)行的只是該測(cè)試函數(shù);而使用參數(shù)化fixture谦秧,每個(gè)使用該fixture的測(cè)試函數(shù)都可以被運(yùn)行多次竟纳,這一特性非常強(qiáng)大撵溃。
第四章 內(nèi)置fixture
tmpdir和tmpdir_factory
內(nèi)置的tmpdir
和tmpdir_factory
負(fù)責(zé)在測(cè)試開(kāi)始運(yùn)行前創(chuàng)建臨時(shí)文件或目錄,并在測(cè)試結(jié)束后刪除蚁袭。單個(gè)測(cè)試使用tmpdir
征懈,多個(gè)測(cè)試使用tmpdir_factory
tmpdir
的作用范圍是函數(shù)級(jí)別,tmpdir_factory
的是會(huì)話級(jí)別 ,如果需要其他級(jí)別的揩悄,需要?jiǎng)?chuàng)建一個(gè)新的fixture卖哎。
def test_tmpdir(tmpdir):
a_file=tmpdir.join("a.txt")
b_dir=tmpdir.mkdir("something")
b_file=b_dir.join("b.txt")
a_file.write("aaa")
b_file.write("bbb")
assert a_file.read()=="aaa" and b_file.read()=="bbb"
pytestconfig
內(nèi)置的pytestconfig可以通過(guò)命令行參數(shù),選項(xiàng)删性,配置文件亏娜,插件,運(yùn)行目錄等方式來(lái)控制pytest蹬挺。它是request.config的快捷方式维贺,被稱為“pytest配置對(duì)象”
def pytest_addoption(parser): #pytest的hook函數(shù)pytest_addoption,可添加命令行選項(xiàng)
parser.addoption("--myopt",action="store_true",help="some my option")
parser.addoption("--foo",action="store",default="bar",help="foo:bar or baz")
def test_option(pytestconfig):
print(pytestconfig.gettoption('myopt'))
print(pytestconfig.gettoption('foo'))
print(pytestconfig.option.foo)
# 一些例子
def test_pytestconfig(pytestconfig):
print(pytestconfig.args)
print(pytestconfig.inifile)
print(pytestconfig.invocation_dir)
print(pytestconfig.rootdir)
print(pytestconfig.getoption('showlocals'))
使用cache
cache用于測(cè)試會(huì)話傳遞給下一段會(huì)話
--last-failed(僅運(yùn)行上次未通過(guò)的)和--failed-first (之前未通過(guò)的首先運(yùn)行)很好的展示cache的功能巴帮,看看cache是如何存儲(chǔ)這些標(biāo)識(shí)數(shù)據(jù)的溯泣。
--cache-show
可以顯示cache存儲(chǔ)的信息
--clear-cache
運(yùn)行前清空cache緩存
def test_cache(cache):
cache.get(key,default)
cache.set(key,value)
使用capsys
允許使用代碼讀取stdout和stderr,capsys.redouterr()
也可以臨時(shí)禁止抓取日志輸出capsys.redouterr()
榕茧。
pytest通常會(huì)抓取輸出垃沦,僅當(dāng)全部用例結(jié)束后,抓取到的日志才會(huì)顯示出來(lái)用押。--s
參數(shù)可以關(guān)閉這個(gè)功能肢簿,在測(cè)試運(yùn)行期就把輸出直接發(fā)送到stdout,但有時(shí)可能只需要部分信息蜻拨,則可以用 capsys.disabled()
臨時(shí)讓輸出繞過(guò)默認(rèn)的輸出捕獲機(jī)制
capsys.redouterr()
def test_disabled(capsys):
with.capsys.disabled():
print("aaaa")
print("bbb") # pytest -q 和 pytest -q -s的區(qū)別
monkeypatch
在運(yùn)行期間對(duì)類或模塊進(jìn)行動(dòng)態(tài)修改池充。常用于替換被測(cè)試代碼的部分運(yùn)行環(huán)境,或?qū)⑤斎胍蕾嚮蜉敵鲆蕾囂鎿Q成更容易測(cè)試的對(duì)象或函數(shù)缎讼。測(cè)試結(jié)束后收夸,無(wú)論結(jié)果是通過(guò)還是失敗,代碼都會(huì)復(fù)原(所有修改都會(huì)撤銷)
例如:修改環(huán)境變量monkey.setenv('HOME',tmpdir.mkdir('home'))
其他函數(shù)(setattr )