欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)邀請(qǐng)碼778899分享:pytest

柚子快報(bào)邀請(qǐng)碼778899分享:pytest

http://yzkb.51969.com/

pytest命名規(guī)則

文件名類方法函數(shù)谷歌風(fēng)格命名規(guī)范Google Python命名規(guī)范-易微幫

pytest測(cè)試用例編寫規(guī)則

類型規(guī)則文件test_開(kāi)頭或者_(dá)test結(jié)尾類Test開(kāi)頭方法/函數(shù)test開(kāi)頭測(cè)試類中不可添加__init__構(gòu)造函數(shù)

pycharm配置與界面化運(yùn)行

首先進(jìn)行添加pytest環(huán)境?其次在settings中的搜索框搜索pytest在default test runner中選擇pytest

?pytest用例結(jié)構(gòu)

用例結(jié)構(gòu)(缺一不可)

用例名稱用例步驟用例斷言

def test_XXX(self):

# 測(cè)試步驟1

# 測(cè)試步驟2

# 斷言 實(shí)際結(jié)果 對(duì)比 預(yù)期結(jié)果

assert ActualResult == ExpectedResult

?類級(jí)別的用例示例

class TestXXX:

def setup(self):

# 資源準(zhǔn)備

pass

def teardown(self):

# 資源銷毀

pass

def test_XXX(self):

# 測(cè)試步驟1

# 測(cè)試步驟2

# 斷言 實(shí)際結(jié)果 對(duì)比 預(yù)期結(jié)果

assert ActualResult == ExpectedResult

用例斷言

概念:斷言(assertion)是一種在程序中的一階邏輯(如:一個(gè)結(jié)果為真或假的邏輯判斷式),目的為了表示與驗(yàn)證軟件開(kāi)發(fā)者預(yù)期的結(jié)果——當(dāng)程序執(zhí)行到斷言的位置時(shí),對(duì)應(yīng)的斷言應(yīng)該為真。若斷言不為真時(shí),程序會(huì)中止執(zhí)行,并給出錯(cuò)誤信息

斷言寫法

assert <表達(dá)式>assert <表達(dá)式>,<描述>

示例1

def test_sum():

a = 1

b = 2

expect = 3

assert a + b == expect,f'{a} +  = {expect} ,結(jié)果為真'

示例2//查看當(dāng)前環(huán)境下是否為linux環(huán)境

import sys

def test_plat():

assert ('linux' in sys.platform), "該代碼只能在 Linux 下執(zhí)行"

?pytest測(cè)試結(jié)構(gòu)框架(set up/tear down)

set up為一些準(zhǔn)備的前置工作tear down為完成一些后置工作

類型規(guī)則setup_module/teardown_module全局模塊級(jí)setup_class/teardown_class類級(jí),只在類中前后運(yùn)行一次(一般常用???????)setup_function/teardown_function函數(shù)級(jí),在類外setup_method/teardown_method方法級(jí),類中的每個(gè)方法執(zhí)行前后setup/teardown在類中,運(yùn)行在調(diào)用方法的前后(一般常用???????)

def test_case1():

print('case1')

def setup_function():

print("資源準(zhǔn)備,setup function")

def teardown_function():

print('資源已損毀 teardown_function')

運(yùn)行代碼后,在終端開(kāi)啟兩個(gè)button,一個(gè)show passed和一個(gè)show ignored,如下圖

def setup_module():

print('資源準(zhǔn)備,setup module')

def teardown_module():

print('資源銷毀,teardown_module')

def test_case1():

print('case1')

def test_case2():

print('case2')

def setup_function():

print("資源準(zhǔn)備,setup function")

def teardown_function():

print('資源已損毀 teardown_function')

運(yùn)行結(jié)果是:

pytest_study.py::test_case1 資源準(zhǔn)備,setup module //module級(jí)別的只執(zhí)行一次

資源準(zhǔn)備,setup function //一般每執(zhí)行一次測(cè)試用例就會(huì)執(zhí)行一次

PASSED [ 50%]case1

資源已損毀 teardown_function

pytest_study.py::test_case2 資源準(zhǔn)備,setup function

PASSED [100%]case2

資源已損毀 teardown_function

資源銷毀,teardown_module

============================== 2 passed in 0.01s ===============================

?pytest 參數(shù)化

通過(guò)參數(shù)的方式傳遞數(shù)據(jù),從而實(shí)現(xiàn)數(shù)據(jù)和腳本分離并且可以實(shí)現(xiàn)用力的重復(fù)生成與執(zhí)行

參數(shù)化實(shí)現(xiàn)方案

裝飾器:@pytest.mark.parametrize

測(cè)試登陸場(chǎng)景

測(cè)試登陸成功,登陸失敗(賬號(hào)錯(cuò)誤,密碼錯(cuò)誤)創(chuàng)建多種賬號(hào),中文文本賬號(hào),英文文本賬號(hào)

不使用pytest

def test_param_login_ok():

# 登錄成功

username = "right"

password = "right"

login(username,password)

def test_param_login_fail():

# 登錄失敗

username = "wrong"

password = "wrong"

login(username,password)

使用pytest的場(chǎng)景

@pytest.mark.parametrize("username,password",[["right","right"],["wrong","wrong"]])

def test_param(username,password):

login(username,password)

?參數(shù)化測(cè)試函數(shù)使用

單參數(shù)

每一條測(cè)試數(shù)據(jù)就會(huì)生成一個(gè)測(cè)試用例 search_list = ['appium', 'selenium', 'pytest']

@pytest.mark.parametrize('search_key', ['appium', 'pytest', 'allure', 'abc'])

def test_search_param(search_key):

assert search_key in search_list

多參數(shù)

# 第二種:多參數(shù)情況,用列表嵌套列表的方式

@pytest.mark.parametrize("username,password", [["rightusername", "right username"],

["wrong username", "wrong password"],

[" ", "password"]

])

def test_login(username, password):

print(f"登陸的用戶名:{username},登陸的密碼:{password}")

默認(rèn)的命名方式測(cè)試數(shù)據(jù)用“-”相連接 如“pytest.pytest_study.test_login”

???????

用例重命名

# 第二種:多參數(shù)情況,用列表嵌套列表的方式

@pytest.mark.parametrize("username,password", [["rightusername", "right username"],

["wrong username", "wrong password"],

[" ", "password"]

],

ids = ["正常的用戶和正確的密碼","錯(cuò)誤的用戶名和錯(cuò)誤的密碼","用戶名為空"]

)

def test_login(username, password):

print(f"登陸的用戶名:{username},登陸的密碼:{password}")

#第三種給我們的用例進(jìn)行重命名,默認(rèn)的命名方式測(cè)試數(shù)據(jù)用“-”相連接 如“pytest.pytest_study.test_login”

如上這樣我們的運(yùn)行結(jié)果是不支持中文的,如下為運(yùn)行后的結(jié)果

?如想要其支持中文的話,需要在文件夾內(nèi)添加conftest.py

# 創(chuàng)建conftest.py 文件 ,將下面內(nèi)容添加進(jìn)去,運(yùn)行腳本

def pytest_collection_modifyitems(items):

"""

測(cè)試用例收集完成時(shí),將收集到的用例名name和用例標(biāo)識(shí)nodeid的中文信息顯示在控制臺(tái)上

"""

for i in items:

i.name=i.name.encode("utf-8").decode("unicode_escape")

i._nodeid=i.nodeid.encode("utf-8").decode("unicode_escape")

如上運(yùn)行結(jié)果,測(cè)試用例將被重命名為中文的格式

笛卡爾積(在接口測(cè)試中應(yīng)用比較廣)

兩組數(shù)據(jù)a = [1,2,3]b = [a,b,c]對(duì)應(yīng)有幾種組形式(1,a)(1,b)(1,c)(2,a)(2,b)(2,c)(3,a)(3,b)(3,c) @pytest.mark.parametrize("b", ["a", "b", "c"])

@pytest.mark.parametrize("a", [1, 2, 3])

def test_param1(a,b):

print(f'笛卡爾積形式的參數(shù)中a = {a},b = ')

? ? ? ? ? ? ? ?測(cè)試結(jié)果如下:

????????????????

pytest標(biāo)記測(cè)試用例

pytest設(shè)置跳過(guò)及預(yù)期失敗測(cè)試用例

調(diào)試時(shí)不想運(yùn)行這個(gè)用例標(biāo)記無(wú)法在某些平臺(tái)上運(yùn)行的測(cè)試功能在某些版本中執(zhí)行,其他版本中跳過(guò)比如:當(dāng)前的外部資源不可用時(shí)跳過(guò)

如果測(cè)試數(shù)據(jù)是從數(shù)據(jù)庫(kù)中取到的,連接數(shù)據(jù)庫(kù)的功能如果返回結(jié)果未成功就跳過(guò),因?yàn)閳?zhí)行也都報(bào)錯(cuò)解決 1:添加裝飾器

無(wú)條件跳過(guò)@pytest.mark.skip

??????????????使用方法:@pytest.mark.skip標(biāo)記在需要跳過(guò)的測(cè)試用例上。 @pytest.mark.skip

def test_login():

print('該條測(cè)試用例未開(kāi)發(fā)完成')

assert True

有條件跳過(guò)@pytest.mark.skipif(reason = 'xxx')//需要添加具體的原因

??????? @pytest.mark.skipif(reson = '代碼未實(shí)現(xiàn)')

def test_bbb():

print('該條測(cè)試用例,代碼未實(shí)現(xiàn)')

assert False 執(zhí)行完成后:

解決 2:代碼中添加跳過(guò)代碼

pytest.skip(reason) def check_login():

return True

def test_function():

print('start')

# 如果未登陸則跳過(guò)后續(xù)步驟

if not check_login():

pytest.skip('unsupported configuration')

print('end')

?在mac上跳過(guò),在windows上運(yùn)行 import sys

import pytest

print(sys.platform)

@pytest.mark.skipif(sys.platform == 'darwin',reason='does not run on mac')

def test_aaa():

assert True

@pytest.mark.skipif(sys.platform == 'win',reason='does not run on windows')

def test_bbb():

assert True xfail使用場(chǎng)景:

?與skip類似,預(yù)期結(jié)果為fail,標(biāo)記用例為fail用法:添加裝飾器@pytest.mark.xfail

?pytest運(yùn)行用例

運(yùn)行 某個(gè)/多個(gè) 用例包運(yùn)行 某個(gè)/多個(gè) 用例模塊運(yùn)行 某個(gè)/多個(gè) 用例類運(yùn)行 某個(gè)/多個(gè) 用例方法

pytest只執(zhí)行上次失敗的測(cè)試用例

--lf(--last-failed)?只重新運(yùn)行故障。--ff(--failed-first)?先運(yùn)行故障然后再運(yùn)行其余的測(cè)試pytest文檔26-運(yùn)行上次失敗用例(--lf 和 --ff)_weixin_34292959的博客-CSDN博客

?常用命令行

?python執(zhí)行pytest代碼

使用main函數(shù)使用python -m pytest 調(diào)用pytest(jeckins持續(xù)集成)

if __name__ == '__main__': ? ? # 1、運(yùn)行當(dāng)前目錄下所有符合規(guī)則的用例,包括子目錄(test_*.py 和 *_test.py) ? ?

pytest.main() ? ? # 2、運(yùn)行test_mark1.py::test_dkej模塊中的某一條用例 ? ? pytest.main(['test_mark1.py::test_dkej','-vs']) ? ? # 3、運(yùn)行某個(gè) 標(biāo)簽 ? ? pytest.main(['test_mark1.py','-vs','-m','dkej']) 運(yùn)行方式 `python test_*.py `

常用的異常處理方法

Pytest如何對(duì)捕獲的異常的類型和內(nèi)容進(jìn)行斷言_pytest捕獲異常_redrose2100的博客-CSDN博客

?pytest結(jié)合數(shù)據(jù)驅(qū)動(dòng)-yaml

什么是數(shù)據(jù)驅(qū)動(dòng)

數(shù)據(jù)驅(qū)動(dòng)就是數(shù)據(jù)的改變從而驅(qū)動(dòng)自動(dòng)化測(cè)試的執(zhí)行,最終引起測(cè)試結(jié)果的改變,簡(jiǎn)單來(lái)說(shuō),就是參數(shù)化的應(yīng)用,

數(shù)據(jù)量小的測(cè)試用例可以使用代碼的參數(shù)化來(lái)實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng),數(shù)據(jù)量大的情況下使用結(jié)構(gòu)化的文件(例如yaml,json)來(lái)對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ),然后用測(cè)試用例讀取這些數(shù)據(jù)應(yīng)用:

app、web、接口自動(dòng)化測(cè)試測(cè)試步驟的數(shù)據(jù)驅(qū)動(dòng)測(cè)試數(shù)據(jù)的數(shù)據(jù)驅(qū)動(dòng)配置的數(shù)據(jù)驅(qū)動(dòng)

yaml文件介紹

對(duì)象:鍵值對(duì)的集合,用冒號(hào)“:”表示數(shù)組:一組按次序排列的值,前加 “-”純量:?jiǎn)蝹€(gè)的,不可再分的值

字符串布爾值整數(shù)浮點(diǎn)數(shù)NULL時(shí)間日期

# 編程語(yǔ)言

languages: # 相當(dāng)于是一對(duì)鍵值 languages:["php","Java","Python"]

- PHP

- Java

- Python

book:

Python入門: # 書籍名稱

price: 55.5

author: Lily

available: True

repertory: 20

date: 2018-02-17

Java入門:

price: 60

author: Lily

available: False

repertory: Null

date: 2018-05-11

yaml文件使用

查看yaml文件

pycharmtxt記事本讀取yaml文件

安裝:pip install pyyaml方法:yaml.safe_load(f) #將yaml轉(zhuǎn)化為python對(duì)象方法:yaml.safe_dump(f)#將python對(duì)象轉(zhuǎn)化為yaml文件 import yaml

file_path = './my.yaml'

with open(file_path, 'r', encoding='utf-8') as f:

data = yaml.safe_load(f)

工程目錄文件?

data 目錄:存放 yaml 數(shù)據(jù)文件func 目錄:存放被測(cè)函數(shù)文件testcase 目錄:存放測(cè)試用例文件

ps:創(chuàng)建data時(shí),可以創(chuàng)建為文件夾,也可以創(chuàng)建為packages

?operation.py#被測(cè)函數(shù)

def my_add(x, y):

result = x + y

return result

test_add.py#測(cè)試case

import pytest

from data_driver_yaml.func.operation import my_add#如果不寫這個(gè)會(huì)造成 下面的my_add函數(shù)找不到,會(huì)報(bào)錯(cuò)

class TestWithYAML:

@pytest.mark.parametrize('x,y,expected', [[1, 1, 2],[1,2,3],[5,6,7]])

def test_add(self, x, y, expected):

assert my_add(int(x), int(y)) == int(expected)

當(dāng)測(cè)試數(shù)據(jù)量很大時(shí),我們可以從yaml中再讀取出來(lái)數(shù)據(jù)

import pytest

import yaml

from data_driver_yaml.func.operation import my_add

#windows電腦需要將with open中再添加一個(gè)參數(shù) encoding = “utf-8”

def get_data():

with open("../data/data.yaml") as f:

data = yaml.safe_load(f)

return data

def test_get_data():

print(get_data())

class TestWithYAML:

@pytest.mark.parametrize('x,y,expected', get_data())

def test_add(self, x, y, expected):

assert my_add(int(x), int(y)) == int(expected)

data_yaml#測(cè)試數(shù)據(jù)

#嵌套三個(gè)列表[[1,1,2],[3,6,9],[100,200,300]]

-

- 1

- 1

- 2

-

- 3

- 6

- 9

-

- 100

- 200

- 300

pytest結(jié)合數(shù)據(jù)驅(qū)動(dòng)Excel

第三方庫(kù)

xlrdxlwingspandas openpyxl

官方文檔: https://openpyxl.readthedocs.io/en/stable/openpyxl庫(kù)的安裝

安裝:pip install openpyxl導(dǎo)入:import openpyxl

import openpyxl

# 獲取工作簿

book = openpyxl.load_workbook('../data/params.xlsx')

# 讀取工作表

sheet = book.active

# 讀取單個(gè)單元格

cell_a1 = sheet['A1']

cell_a3 = sheet.cell(column=1, row=3) # A3

# 讀取多個(gè)連續(xù)單元格

cells = sheet["A1":"C3"]

# 獲取單元格的值

cell_a1.value

注意xlsx文件必須用wps進(jìn)行創(chuàng)建,在文件下創(chuàng)建file重命名為xlsx文件會(huì)出現(xiàn)報(bào)錯(cuò)的問(wèn)題

testcases.py文件

from openpyxl_study.read_excel.func.operation import my_add

import pytest

import openpyxl

def get_excel():

book = openpyxl.load_workbook("../data/params.xlsx")

sheet = book.active

cells = sheet["A1":"C3"]

print(cells)

values = []

for row in cells:

data = []

for cell in row:

data.append(cell.value)

values.append(data)

return values

class TestWithEXCEL:

@pytest.mark.parametrize('x,y,expected', get_excel())

def test_add(self, x, y, expected):

assert my_add(int(x), int(y)) == int(expected)

pytest結(jié)合csv實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)

csv文件介紹

csv:逗號(hào)分隔值是comma-separated values的縮寫是純文本形式存儲(chǔ)數(shù)字和文本文件由任意數(shù)目的記錄組成每行記錄由多個(gè)字段組成

以下例子:

Linux從入門到高級(jí),linux,¥5000

web自動(dòng)化測(cè)試進(jìn)階,python,¥3000

app自動(dòng)化測(cè)試進(jìn)階,python,¥6000

Docker容器化技術(shù),linux,¥5000

測(cè)試平臺(tái)開(kāi)發(fā)與實(shí)戰(zhàn),python,¥8000

讀取數(shù)據(jù)

內(nèi)置函數(shù):open()內(nèi)置模塊:csv //有相關(guān)讀取csv文件的方法

??????????????方法:csv.reader(iterable)

參數(shù):iterable ,文件或列表對(duì)象返回:迭代器,每次迭代會(huì)返回一行數(shù)據(jù)。

工程目錄結(jié)構(gòu)

# 工程目錄結(jié)構(gòu)

.

├── data

│ └── params.csv

├── func

│ ├── __init__.py

│ └── operation.py

└── testcase

├── __init__.py

└── test_add.py

data 目錄:存放 csv 數(shù)據(jù)文件func 目錄:存放被測(cè)函數(shù)文件testcase 目錄:存放測(cè)試用例文件

import pytest

import csv

from openpyxl_study.read_csv.func.operation import my_add

def get_csv():

with open("../data/demo.csv") as f:

#讀取這個(gè)文件

raw = csv.reader(f)

data = []

for line in raw:

data.append(line)

print(data)

return data

class TestWithCsv:

@pytest.mark.parametrize('x,y,expected',get_csv())

def test_add(self,x,y,expected):

assert my_add(int(x),int(y)) == int(expected)

pytest結(jié)合數(shù)據(jù)驅(qū)動(dòng)json

json是js對(duì)象全稱是javascript object notation是一種輕量級(jí)的數(shù)據(jù)交換格式j(luò)son結(jié)構(gòu)

對(duì)象{'key':value}數(shù)組[value1,value2....]例子 {

"name:": "hogwarts ",

"detail": {

"course": "python",

"city": "北京"

},

"remark": [1000, 666, 888]

} 查看 json 文件

pycharmtxt 記事本讀取 json 文件

內(nèi)置函數(shù) open()內(nèi)置庫(kù) json方法:json.loads() //返回值是dict 字典格式的方法:json.dumps() //返回值是字符串類型的格式

import json

def get_json():

with open("demo.json") as file:

data = json.load(file)

print(data,type(data))

s = json.dumps(data,ensure_ascii=False)

print(s,type(s))

if __name__ == "__main__":

get_json()

運(yùn)行結(jié)果是:

{'name:': 'hogwarts ', 'detail': {'course': 'python', 'city': '北京'}, 'remark': [1000, 666, 888]}

{"name:": "hogwarts ", "detail": {"course": "python", "city": "北京"}, "remark": [1000, 666, 888]}

{

"case1": [1, 1, 2],

"case2": [3, 6, 9],

"case3": [100, 200, 300]

}

import json

from json_study.func.operation import my_add

import pytest

def get_json():

with open("../data/params.json",'r') as file:

data = json.loads(file.read())

print(data)

return list(data.values())

class TestWithJSON:

@pytest.mark.parametrize('x,y,expected', get_json())

def test_add(self, x, y, expected):

assert my_add(int(x), int(y)) == int(expected)

4. 使用values()方法取值

Python字典提供了values()方法,該方法可以將字典的所有值以列表(list)的形式返回。我們可以通過(guò)遍歷列表來(lái)取出對(duì)應(yīng)的值。具體可以通過(guò)以下方式實(shí)現(xiàn):

```

person = {"name": "張三", "age": 18, "gender": "男"}

for value in person.values():

print(value)

```

在上述代碼中,我們使用for循環(huán)遍歷了字典person中的所有值,然后使用value變量取出對(duì)應(yīng)的值。輸出結(jié)果為:

```

張三

18

```

需要注意的是,values()方法返回的值是無(wú)序的,因此輸出結(jié)果的順序與字典中各個(gè)鍵值對(duì)的順序無(wú)關(guān)。

?Fixture用法

Python測(cè)試框架pytest(04)fixture - 測(cè)試用例調(diào)用fixture、fixture傳遞測(cè)試數(shù)據(jù)_pytest用例之間值傳遞fixture_wangmcn的博客-CSDN博客

Fixture特點(diǎn)及優(yōu)勢(shì)

命令靈活:對(duì)于setup,teardown,可以不起這兩個(gè)名字?jǐn)?shù)據(jù)共享:在conftest.py配置里寫方法可以實(shí)現(xiàn)數(shù)據(jù)共享,不需要import導(dǎo)入,可以跨文件共享scope的層次及神奇的yield組合相當(dāng)于各種setup和teardown實(shí)現(xiàn)參數(shù)化

fixture在自動(dòng)化中的應(yīng)用

場(chǎng)景測(cè)試用例執(zhí)行時(shí),有時(shí)用例需要登陸才能執(zhí)行,有些不需要登陸。setup和teardown無(wú)法滿足,fixture可以。默認(rèn)scope(范圍)function步驟

導(dǎo)入pytest在登陸的函數(shù)上面加@pytest.fixture()在要使用的測(cè)試方法中傳入(登陸函數(shù)名稱)不穿入的就不登陸直接執(zhí)行測(cè)試方法 import pytest

def login():

print("登陸操作")

def test_search():

print("搜索")

def test_cart():

login()

print("購(gòu)物車")

def test_order():

login()

print("購(gòu)物車") import pytest

@pytest.fixture()

def login():

print("登陸操作")

def test_search():

print("搜索")

def test_cart(login):

print("購(gòu)物車")

def test_order(login):

print("購(gòu)物車")

?yield的用法

場(chǎng)景:

你已經(jīng)可以將測(cè)試方法【當(dāng)前要執(zhí)行的或依賴的】解決了,測(cè)試方法后銷毀清楚數(shù)據(jù)的要如何進(jìn)行呢?解決:

通過(guò)在fixture函數(shù)中加入yield關(guān)鍵字,yield時(shí)調(diào)用第一次返回結(jié)果,第二次執(zhí)行他下面的語(yǔ)句返回步驟:

在@pytest.fixture(scope=module)在登陸的方法中加yield,之后加銷毀清除的步驟

import pytest

@pytest.fixture()

def login():

# setup操作

print("登陸操作")

token = '123456'

username = 'hogwarts'

yield token, username#相當(dāng)于return

#teardown操作

print('完成登出操作')

def test_search(login):

token,username = login

print(f'token:{token},username:{username}')

print("搜索")

?fixture在自動(dòng)化中的應(yīng)用-數(shù)據(jù)共享

場(chǎng)景:

你與其他測(cè)試工程師合作一起開(kāi)發(fā)時(shí),公共的模塊要在不同文件中,要在大家都訪問(wèn)到的地方解決:

使用conftest.py這個(gè)文件進(jìn)行數(shù)據(jù)共享,并且它可以放在不同位置起著不同范圍的共享作用前提:

conftest文件名是不能換的放在項(xiàng)目下是全局的數(shù)據(jù)共享的地方執(zhí)行:

系統(tǒng)執(zhí)行到參數(shù)login時(shí)先從本模塊中查找是否有這個(gè)名字的變量之后在conftest.py中找是否有步驟:

將登陸模塊帶@pytest.fixture寫在conftest.py

?conftest.py

import pytest

@pytest.fixture()

def login():

# setup操作

print("登陸操作")

token = '123456'

username = 'hogwarts'

yield token, username#相當(dāng)于return

#teardown操作

print('完成登出操作')

test_fixturedemo1.py

def test_search(login):

token,username = login

print(f'token:{token},username:{username}')

print("搜索")

def test_cart(login):

print("購(gòu)物車")

def test_order(login):

print("購(gòu)物車")

?fixture在自動(dòng)化中的應(yīng)用-自動(dòng)應(yīng)用

場(chǎng)景:

不想原測(cè)試方法有任何改動(dòng),或全部都自動(dòng)實(shí)現(xiàn)自動(dòng)應(yīng)用,沒(méi)特例,也都不需要返回值時(shí)可以選擇自動(dòng)應(yīng)用解決:

使用fixture中參數(shù)autouse=True實(shí)現(xiàn)步驟:

在放上面加@pytest.fixture(autouse = True)

conftest.py

import pytest

@pytest.fixture(scope="function",autouse=True)

def login():

# setup操作

print("登陸操作")

token = '123456'

username = 'hogwarts'

yield token, username#相當(dāng)于return

#teardown操作

print('完成登出操作')

?test_fixturedemo1.py

def test_search(login):

token,username = login

print(f'token:{token},username:{username}')

print("搜索")

def test_cart():

print("購(gòu)物車")

def test_order():

print("購(gòu)物車")

在test方法中沒(méi)有調(diào)用login參數(shù)的測(cè)試用例,也會(huì)默認(rèn)加了login,在執(zhí)行每個(gè)測(cè)試用例之前,都會(huì)執(zhí)行一遍登入登出操作

fixture在自動(dòng)化中的應(yīng)用-參數(shù)化

場(chǎng)景:

測(cè)試離不開(kāi)數(shù)據(jù),為了數(shù)據(jù)靈活,一般數(shù)據(jù)都是通過(guò)參數(shù)傳的解法

fixture通過(guò)固定參數(shù)request傳遞步驟

在fixture中增加@pytest.fixture(params=[1,2,3,'linda'])在方法參數(shù)寫request,方法體里面使用request.param接收參數(shù)

import pytest

@pytest.fixture(params=["selenium","appium"])

def login(request):

print(f"用戶名:{request.param}")

return request.param

def test_demo1(login):

print(f"demo1 case:數(shù)據(jù)為:{login}")

運(yùn)行結(jié)果是:

/Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/venv/bin/python /Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py --target test_fixture_param.py::test_demo1

Testing started at 07:48 ...

Launching pytest with arguments test_fixture_param.py::test_demo1 --no-header --no-summary -q in /Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/test_fixture

============================= test session starts ==============================

collecting ... collected 2 items

test_fixture_param.py::test_demo1[selenium] 用戶名:selenium

PASSED [ 50%]demo1 case:數(shù)據(jù)為:selenium

test_fixture_param.py::test_demo1[appium] 用戶名:appium

PASSED [100%]demo1 case:數(shù)據(jù)為:appium

============================== 2 passed in 0.01s ===============================

Process finished with exit code 0

使用?yield可以讓每條測(cè)試用例執(zhí)行yield后的語(yǔ)句,return的話將不會(huì)執(zhí)行return后的語(yǔ)句

import pytest

@pytest.fixture(params=["selenium","appium"])

def login(request):

print(f"用戶名:{request.param}")

yield request.param

print("完成登出操作")

def test_demo1(login):

print(f"demo1 case:數(shù)據(jù)為:{login}")

運(yùn)行結(jié)果是:

/Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/venv/bin/python /Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py --path /Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/test_fixture/test_fixture_param.py

Testing started at 07:49 ...

Launching pytest with arguments /Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/test_fixture/test_fixture_param.py --no-header --no-summary -q in /Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/test_fixture

============================= test session starts ==============================

collecting ... collected 2 items

test_fixture_param.py::test_demo1[selenium] 用戶名:selenium

PASSED [ 50%]demo1 case:數(shù)據(jù)為:selenium

完成登出操作

test_fixture_param.py::test_demo1[appium] 用戶名:appium

PASSED [100%]demo1 case:數(shù)據(jù)為:appium

完成登出操作

============================== 2 passed in 0.01s ===============================

Process finished with exit code 0

pytest.ini是什么

pytest.ini是pytest的配置文件可以修改pytest的默認(rèn)行為不能使用任何中文符號(hào),包括漢字、空格、引號(hào)、冒號(hào)等等

pytest.ini

修改用例的命名規(guī)則配置日志格式,比代碼配置更方便添加標(biāo)簽,防止運(yùn)行過(guò)程報(bào)警告錯(cuò)誤制定執(zhí)行目錄排除搜索目錄

pytest配置-改變運(yùn)行規(guī)則

pytest.ini ? ? ? ? ? ? //是用來(lái)配置哪些命名方式的函數(shù)、類或者python文件可以運(yùn)行check_demo.py //以check_開(kāi)頭命名的測(cè)試文件test_first.py ? ? ? //以test_開(kāi)頭命名的測(cè)試文件

pytest.ini

[pytest]

;執(zhí)行check_開(kāi)頭和 test_開(kāi)頭的所有的文件,后面一定要加*

python_files = check_* test_*

;執(zhí)行所有的以Test和Check開(kāi)頭的類

python_classes = Test* Check*

;執(zhí)行所有以test_和check_開(kāi)頭的方法

python_functions= test_* check_*

check_demo.py //check開(kāi)頭的類及函數(shù)也是需要執(zhí)行

class CheckDemo:

def check_demo1(self):

pass

def check_demo2(self):

pass

?test_first.py //test開(kāi)頭的文件名/函數(shù)名/類名也是需要執(zhí)行

import logging

def inc(x):

return x + 1

def test_answer():

logging.info("這是 answer 測(cè)試用例")

logging.info("斷言 assert inc(3) == 5 ")

assert inc(3) == 5

class TestDemo:

def test_demo1(self):

logging.info("這是 demo1 測(cè)試用例")

pass

def test_demo2(self):

logging.info("這是 demo2 測(cè)試用例")

pass

在pytest.ini中添加

addopts = -v -s --alluredir=./results

在終端中鍵入 pytest -vs可以將所有的測(cè)試結(jié)果打印出來(lái)

?

(venv) cangqiongqiyuyunxi@cangqiongqiyuyunxideMacBook-Air testini % pytest -vs

==================================================== test session starts =====================================================

platform darwin -- Python 3.9.6, pytest-7.4.0, pluggy-1.3.0 -- /Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/venv/bin/python

cachedir: .pytest_cache

rootdir: /Users/cangqiongqiyuyunxi/PycharmProjects/pythonProject/testini

configfile: pytest.ini

collected 3 items

test_first.py::test_answer FAILED

test_first.py::TestDemo::test_demo1 PASSED

test_first.py::TestDemo::test_demo2 PASSED

========================================================== FAILURES ==========================================================

________________________________________________________ test_answer _________________________________________________________

def test_answer():

logging.info("這是 answer 測(cè)試用例")

logging.info("斷言 assert inc(3) == 5 ")

> assert inc(3) == 5

E assert 4 == 5

E + where 4 = inc(3)

test_first.py:12: AssertionError

================================================== short test summary info ===================================================

FAILED test_first.py::test_answer - assert 4 == 5

================================================ 1 failed, 2 passed in 0.04s =================================================

pytest配置-指定/忽略執(zhí)行目錄

;設(shè)置執(zhí)行的路徑

;testpaths = bilibili baidu

;忽略某些文件夾/目錄

norecursedirs = result logs datas test_demo*

pytest logging收集日志

[pytest]

;日志開(kāi)關(guān) true false

log_cli = true

;日志級(jí)別

log_cli_level = info

;打印詳細(xì)日志,相當(dāng)于命令行加 -vs

addopts = --capture=no

;日志格式

log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)

;日志時(shí)間格式

log_cli_date_format = %Y-%m-%d %H:%M:%S

;日志文件位置

log_file = ./log/test.log

;日志文件等級(jí)

log_file_level = info

;日志文件格式

log_file_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)

;日志文件日期格式

log_file_date_format = %Y-%m-%d %H:%M:%S

log_file = ./log/test.log會(huì)將logging的輸出存放在test.log中

pytest插件開(kāi)發(fā)[進(jìn)階]

pytest插件分類

外部插件:pip install 安裝的插件本地插件:pytest自動(dòng)模塊發(fā)現(xiàn)機(jī)制(conftest.py存放的)內(nèi)置插件:代碼內(nèi)部的_pytest目錄加載pytest hook介紹pytest hook執(zhí)行順序pytest常用插件

pip install pytest-ordering 控制用例的執(zhí)行順序(重點(diǎn))

pip install pytest-xdist 分布式并發(fā)執(zhí)行測(cè)試用例(重點(diǎn))

pip install pytest-dependency 控制用例的依賴關(guān)系 (了解)

pip install pytest-rerunfailures 失敗重跑(了解)

pip install pytest-assume 多重較驗(yàn)(了解)

pip install pytest-random-order 用例隨機(jī)執(zhí)行(了解)

pip install pytest-html 測(cè)試報(bào)告(了解) 可以通過(guò)???????PyPI · The Python Package Index 搜索pytest看相關(guān)的插件 pytest執(zhí)行順序控制

場(chǎng)景:

對(duì)于集成測(cè)試,經(jīng)常會(huì)有上下文依賴關(guān)系的測(cè)試用例對(duì)于10個(gè)步驟,拆成10條case,這時(shí)候能知道到底執(zhí)行到哪步報(bào)錯(cuò)用例默認(rèn)執(zhí)行順序:自上而下執(zhí)行解決:

可以通過(guò)setup,teardown和fixture來(lái)解決,也可以使用對(duì)應(yīng)的插件安裝:pip install pytest-ordering用法:@pytest.mark.run(order = 2)注意:多個(gè)插件裝飾器(>2)的時(shí)候,有可能會(huì)發(fā)生沖突?

pytest并行與分布式執(zhí)行

場(chǎng)景 1:

測(cè)試用例 1000 條,一個(gè)用例執(zhí)行 1 分鐘,一個(gè)測(cè)試人員執(zhí)行需要 1000 分鐘。

通常我們會(huì)用人力成本換取時(shí)間成本,加幾個(gè)人一起執(zhí)行,時(shí)間就會(huì) 縮短。

如果 10 人一起執(zhí)行只需要 100 分鐘,這就是一種分布式場(chǎng)景。

場(chǎng)景 2:

假設(shè)有個(gè)報(bào)名系統(tǒng),對(duì)報(bào)名總數(shù)統(tǒng)計(jì),數(shù)據(jù)同時(shí)進(jìn)行修改操作的時(shí)候有可能出現(xiàn)問(wèn)題,

需要模擬這個(gè)場(chǎng)景,需要多用戶并發(fā)請(qǐng)求數(shù)據(jù)。

解決:

使用分布式并發(fā)執(zhí)行測(cè)試用例。分布式插件:pytest-xdist

安裝及運(yùn)行:?pip install pytest-xdist

注意:?用例多的時(shí)候效果明顯,多進(jìn)程并發(fā)執(zhí)行,同時(shí)支持 allure

from time import sleep

import pytest

def test_foo():

sleep(1)

assert True

def test_bar():

sleep(1)

assert True

def test_bar1():

sleep(1)

assert True

def test_foo1():

sleep(1)

assert True

def test_bar2():

sleep(1)

assert True

def test_bar3():

sleep(1)

assert True

在終端中執(zhí)行pytest -n auto -vs將會(huì)分布式執(zhí)行我們的測(cè)試用例

如果串型執(zhí)行我們的測(cè)試用例 總共會(huì)用6s的執(zhí)行時(shí)間

?

?如果分布式執(zhí)行我們的測(cè)試用例 我們將大大縮短執(zhí)行我們測(cè)試用例的時(shí)間

?pytest hook介紹

hook是一個(gè)勾子函數(shù)

?hook是個(gè)函數(shù),在系統(tǒng)消息觸發(fā)時(shí)被系統(tǒng)調(diào)用自動(dòng)觸發(fā)機(jī)制hook函數(shù)的名稱是確定的pytest有非常多的勾子函數(shù)使用時(shí)直接編寫函數(shù)體

root

└── pytest_cmdline_main

├── pytest_plugin_registered

├── pytest_configure

│ └── pytest_plugin_registered

├── pytest_sessionstart

│ ├── pytest_plugin_registered

│ └── pytest_report_header

├── pytest_collection #在收集測(cè)試用例時(shí)就需要hook

│ ├── pytest_collectstart

│ ├── pytest_make_collect_report

│ │ ├── pytest_collect_file

│ │ │ └── pytest_pycollect_makemodule

│ │ └── pytest_pycollect_makeitem

│ │ └── pytest_generate_tests

│ │ └── pytest_make_parametrize_id

│ ├── pytest_collectreport

│ ├── pytest_itemcollected

│ ├── pytest_collection_modifyitems

│ └── pytest_collection_finish

│ └── pytest_report_collectionfinish

├── pytest_runtestloop

│ └── pytest_runtest_protocol

│ ├── pytest_runtest_logstart

│ ├── pytest_runtest_setup

│ │ └── pytest_fixture_setup

│ ├── pytest_runtest_makereport

│ ├── pytest_runtest_logreport

│ │ └── pytest_report_teststatus

│ ├── pytest_runtest_call #將會(huì)在調(diào)用測(cè)試用例時(shí)實(shí)現(xiàn)

│ │ └── pytest_pyfunc_call

│ ├── pytest_runtest_teardown

│ │ └── pytest_fixture_post_finalizer

│ └── pytest_runtest_logfinish

├── pytest_sessionfinish

│ └── pytest_terminal_summary

└── pytest_unconfigure

原始鏈接

pytest官方關(guān)于hook的說(shuō)明

https://docs.pytest.org/en/stable/reference.html?#hooks 134

https://docs.pytest.org/en/stable/_modules/_pytest/hookspec.html#pytest_cmdline_parse 76

流程說(shuō)明原始鏈接

https://github.com/pytest-dev/pytest/issues/3261 81

找到hook的源碼:python3.9/site-packages/_pytest/hookspec.py

conftest.py //將setup和teardown引入在測(cè)試用例前后進(jìn)行調(diào)用

from typing import Optional

def pytest_runtest_setup(item: "Item") -> None:

print("setup")

def pytest_runtest_teardown(item: "Item", nextitem: Optional["Item"]) -> None:

print("teardown")

test_hook.py // 實(shí)際跑的測(cè)試用例

def test_demo1():

print("test hook")

?hook函數(shù)總結(jié)

hook函數(shù)名字固定hook函數(shù)會(huì)被自動(dòng)執(zhí)行執(zhí)行時(shí)有先后順序的pytest定義了很多hook函數(shù),可以在不同階段實(shí)現(xiàn)不同的功能

柚子快報(bào)邀請(qǐng)碼778899分享:pytest

http://yzkb.51969.com/

推薦閱讀

評(píng)論可見(jiàn),查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19273703.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問(wèn)

文章目錄