答案是:ABD
def test_XXX(self):
# 测试步骤1
# 测试步骤2
# 断言 实际结果 对比 预期结果
assert ActualResult == ExpectedResult
class TestXXX:
def setup(self):
# 资源准备
pass
def teardown(self):
# 资源销毁
pass
def test_XXX(self):
# 测试步骤1
# 测试步骤2
# 断言 实际结果 对比 预期结果
assert ActualResult == ExpectedResult
assert <表达式>
assert <表达式>,<描述>
def test_a():
assert True
def test_b():
a = 1
b = 1
c = 2
assert a + b == c, f"{a}+{b}=={c}, 结果为真"
def test_c():
a = 1
b = 1
c = 2
assert 'abc' in "abcd"
import sys
def test_plat():
assert ('linux' in sys.platform), "该代码只能在 Linux 下执行"
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.mark.parametrize
@pytest.mark.parametrize("username,password",[["right","right"], ["wrong","wrong"]])
def test_param(username,password):
login(username,password)
search_list = ['appium','selenium','pytest']
@pytest.mark.parametrize('name',search_list)
def test_search(name):
assert name in search_list
import pytest
# 数据放在元组中
@pytest.mark.parametrize("test_input,expected",[
("3+5",8),("2+5",7),("7+5",12)
])
def test_mark_more(test_input,expected):
assert eval(test_input) == expected
# 数据放在列表中
@pytest.mark.parametrize("test_input,expected",[
["3+5",8],["2+5",7],["7+5",12]
])
def test_mark_more(test_input,expected):
assert eval(test_input) == expected
import pytest
@pytest.mark.parametrize("test_input,expected",[
("3+5",8),("2+5",7),("7+5",12)
],ids=['add_3+5=8','add_2+5=7','add_3+5=12'])
def test_mark_more(test_input,expected):
assert eval(test_input) == expected
# 创建conftest.py 文件 ,将下面内容添加进去,运行脚本
def pytest_collection_modifyitems(items):
"""
测试用例收集完成时,将收集到的用例名name和用例标识nodeid的中文信息显示在控制台上
"""
for i in items:
i.name=i.name.encode("utf-8").decode("unicode_escape")
i._nodeid=i.nodeid.encode("utf-8").decode("unicode_escape")
@pytest.mark.parametrize("test_input,expected",[
("3+5",8),("2+5",7),("7+5",12)
],ids=["3和5相加","2和5相加","7和5相加"])
def test_mark_more(test_input,expected):
assert eval(test_input) == expected
两组数据
a=[1,2,3]
b=[a,b,c]
对应有几种组合形势 ?9
(1,a),(1,b),(1,c)
(2,a),(2,b),(2,c)
(3,a),(3,b),(3,c)
import pytest
@pytest.mark.parametrize("b",["a","b","c"])
@pytest.mark.parametrize("a",[1,2,3])
#如果有多个装饰器,由近到远,先a后b,一共有9条案例
def test_param1(a,b):
print(f"笛卡积形式的参数化中 a={a} , b={b}")
pytest -s test_mark_zi_09.py -m=webtest
pytest -s test_mark_zi_09.py -m apptest
pytest -s test_mark_zi_09.py -m "not ios"
@pytest.mark.skip
@pytest.mark.skipif
pytest.skip(reason)
@pytest.skip(reason="这个有Bug")
def test_add_3(self):
#a的参数超出范围
expect = Calculator().add(-100,99)
assert expect == "参数大小超出范围"
@pytest.mark.xfail
pytest/py.test [包名]
pytest 文件名.py
pytest 文件名.py::类名
pytest 文件名.py::类名::方法名
--lf(--last-failed)
只重新运行故障。--ff(--failed-first)
先运行故障然后再运行其余的测试—help
-x 用例一旦失败(fail/error),就立刻停止执行
–maxfail=num 用例达到
-m 标记用例
-k 执行包含某个关键字的测试用例
-v 打印详细日志
-s 打印输出日志(一般-vs一块儿使用)
—collect-only(测试平台,pytest 自动导入功能 )
if __name__ == '__main__':
# 1、运行当前目录下所有符合规则的用例,包括子目录(test_*.py 和 *_test.py)
pytest.main()
# 2、运行test_mark1.py::test_dkej模块中的某一条用例
pytest.main(['test_mark1.py::test_dkej','-vs'])
# 3、运行某个 标签
pytest.main(['test_mark1.py','-vs','-m','dkej'])
运行方式
`python test_*.py `
try:
可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
处理异常的代码块2
except [Exception]:
处理其它异常
def test_raise():
with pytest.raises(ValueError, match='must be 0 or None'):
raise ValueError("value must be 0 or None")
def test_raise1():
with pytest.raises(ValueError) as exc_info:
raise ValueError("value must be 42")
assert exc_info.type is ValueError
assert exc_info.value.args[0] == "value must be 42"
# 编程语言
languages:
- 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
pip install pyyaml
yaml.safe_load(f)
读取yaml文件内容yaml.safe_dump(f)
import yaml
file_path = './my.yaml'
with open(file_path, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
# 工程目录结构
├── data
│ └── data.yaml
├── func
│ ├── __init__.py
│ └── operation.py
└── testcase
├── __init__.py
└── test_add.py
operation.py
test_add.py
data.yaml
# operation.py 文件内容
def my_add(x, y):
result = x + y
return result
# test_add.py 文件内容
class TestWithYAML:
@pytest.mark.parametrize('x,y,expected', [[1, 1, 2]])
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
# data.yaml 文件内容
-
- 1
- 1
- 2
-
- 3
- 6
- 9
-
- 100
- 200
- 300
# 读取yaml文件
def get_yaml():
"""
获取json数据
:return: 返回数据的结构:[[1, 1, 2], [3, 6, 9], [100, 200, 300]]
"""
with open('../datas/data.yaml', 'r') as f:
data = yaml.safe_load(f)
return data
xlrd
xlwings
pandas
pip install openpyxl
import openpyxl
import openpyxl
# 获取工作簿
book = openpyxl.load_workbook('../data/params.xlsx')
# 读取工作表
sheet = book.active
# 读取单个单元格
cell_a1 = sheet['A1']
cell_a3 = sheet.cell(column=1, row=3) # A3
# 读取多个连续单元格
cells = sheet["A1":"C3"]
# 获取单元格的值
cell_a1.value
# 工程目录结构
.
├── data
│ └── params.excel
├── func
│ ├── __init__.py
│ └── operation.py
└── testcase
├── __init__.py
└── test_add.py
operation.py
test_add.py
# operation.py 文件内容
def my_add(x, y):
result = x + y
return result
# test_add.py 文件内容
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)
params.xlsx
# 读取Excel文件
import openpyxl
import pytest
def get_excel():
# 获取工作簿
book = openpyxl.load_workbook('../data/params.xlsx')
# 获取活动行(非空白的)
sheet = book.active
# 提取数据,格式:[[1, 2, 3], [3, 6, 9], [100, 200, 300]]
values = []
for row in sheet:
line = []
for cell in row:
line.append(cell.value)
values.append(line)
return values
csv 文件内容为:
open()
csv
csv.reader(iterable)
# 读取csv文件内容
import csv
def get_csv():
with open('demo.csv', 'r',encoding='utf_8') as file:
raw = csv.reader(file)
for line in raw:
print(line)
get_csv()
#结果为:
# ['Linux从入门到高级', 'linux', '¥5000']
# ['web自动化测试进阶', 'python', '¥3000']
# ['app自动化测试进阶', 'python', '¥6000']
# ['Docker容器化技术', 'linux', '¥5000']
# ['测试平台开发与实战', 'python', '¥8000']
# 工程目录结构
.
├── data
│ └── params.csv
├── func
│ ├── __init__.py
│ └── operation.py
└── testcase
├── __init__.py
└── test_add.py
operation.py
test_add.py
params.csv
# operation.py 文件内容
def my_add(x, y):
result = x + y
return result
# test_add.py 文件内容
class TestWithCSV:
@pytest.mark.parametrize('x,y,expected', [[1, 1, 2]])
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
# params.csv 文件内容
1,1,2
3,6,9
100,200,300
# 读取 data目录下的 params.csv 文件
import csv
def get_csv():
"""
获取csv数据
:return: 返回数据的结构:[[1, 1, 2], [3, 6, 9], [100, 200, 300]]
"""
with open('../data/params.csv', 'r') as file:
raw = csv.reader(file)
data = []
for line in raw:
data.append(line)
return data
#返回值为:[['1', '1', '2'], ['3', '6', '9'], ['100', '200', '300']]
{"key": value}
[value1, value2 ...]
{
"name:": "hogwarts ",
"detail": {
"course": "python",
"city": "北京"
},
"remark": [1000, 666, 888]
}
json.loads()
将json转为字典json.dumps()
# 读取json文件内容
def get_json():
with open('demo.json', 'r') as f:
data = json.loads(f.read())
print(data)
# 工程目录结构
.
├── data
│ └── params.json
├── func
│ ├── __init__.py
│ └── operation.py
└── testcase
├── __init__.py
└── test_add.py
operation.py
test_add.py
params.json
import pytest
# operation.py 文件内容
def my_add(x, y):
result = x + y
return result
# test_add.py 文件内容
class TestWithJSON:
@pytest.mark.parametrize('x,y,expected', [[1, 1, 2]])
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
# params.json 文件内容
{
"case1": [1, 1, 2],
"case2": [3, 6, 9],
"case3": [100, 200, 300]
}
# 读取json文件
import json
def get_json():
"""
获取json数据
:return: 返回数据的结构:[[1, 1, 2], [3, 6, 9], [100, 200, 300]]
"""
with open('demo.json', 'r') as f:
data = json.loads(f.read())
#打印结果:{'case1': [1, 1, 2], 'case2': [3, 6, 9], 'case3': [100, 200, 300]}
print(data)
#打印结果为:dict_values([[1, 1, 2], [3, 6, 9], [100, 200, 300]])
print(data.values())
#返回结果为:[[1, 1, 2], [3, 6, 9], [100, 200, 300]]
return list(data.values())
测试⽤例执⾏时,有的⽤例需要登陆才能执⾏,有些⽤例不需要登陆。
setup 和 teardown ⽆法满⾜。fixture 可以。默认 scope(范围)function
你已经可以将测试⽅法【前要执⾏的或依赖的】解决了,
测试⽅法后销毁清除数据的要如何进⾏呢?
通过在 fixture 函数中加⼊ yield 关键字,yield 是调⽤第⼀次返回结果,
第⼆次执⾏它下⾯的语句返回。
在@pytest.fixture(scope=module)。
在登陆的⽅法中加 yield,之后加销毁清除的步骤
你与其他测试⼯程师合作⼀起开发时,公共的模块要在不同⽂件中,要在⼤家都访问到的地⽅。
使⽤ conftest.py 这个⽂件进⾏数据共享,并且他可以放在不同位置起着不同的范围共享作⽤。
将登陆模块带@pytest.fixture 写在 conftest.py
场景:
不想原测试⽅法有任何改动,或全部都⾃动实现⾃动应⽤,
没特例,也都不需要返回值时可以选择⾃动应⽤
解决:
使⽤ fixture 中参数 autouse=True 实现
步骤:
在⽅法上⾯加 @pytest.fixture(autouse=True)
场景:
测试离不开数据,为了数据灵活,⼀般数据都是通过参数传的
解决:
fixture 通过固定参数 request 传递
步骤:
在 fixture 中增加@pytest.fixture(params=[1, 2, 3, ‘linda’])
在⽅法参数写 request,方法体里面使用 request.param 接收参数
;执行check_开头和 test_开头的所有的文件,后面一定要加*
python_files = check_* test_*
;执行所有的以Test和Check开头的类
python_classes = Test* Check*
;执行所有以test_和check_开头的方法
python_functions= test_* check_*
addopts = -v -s --alluredir=./results
;设置执行的路径
;testpaths = bilibili baidu
;忽略某些文件夹/目录
norecursedirs = result logs datas test_demo*
配置参考链接:pytest logging 收集日志
pip install pytest-ordering 控制用例的执行顺序(重点)
pip install pytest-xdist 分布式并发执行测试用例(重点)
pip install pytest-dependency 控制用例的依赖关系 (了解)
pip install pytest-rerunfailures 失败重跑(了解)
pip install pytest-assume 多重较验(了解)
pip install pytest-random-order 用例随机执行(了解)
pip install pytest-html 测试报告(了解)
场景:
对于集成测试,经常会有上下文依赖关系的测试用例。
比如 10 个步骤,拆成 10 条 case,这时候能知道到底执行到哪步报错。
用例默认执行顺序:自上而下执行
解决:
可以通过 setup,teardown 和 fixture 来解决。也可以使用对应的插件。
安装:pip install pytest-ordering
用法:@pytest.mark.run(order=2)
注意:多个插件装饰器(>2)的时候,有可能会发生冲突
场景 1:
测试用例 1000 条,一个用例执行 1 分钟,一个测试人员执行需要 1000 分钟。
通常我们会用人力成本换取时间成本,加几个人一起执行,时间就会 缩短。
如果 10 人一起执行只需要 100 分钟,这就是一种分布式场景。
场景 2:
假设有个报名系统,对报名总数统计,数据同时进行修改操作的时候有可能出现问题,
需要模拟这个场景,需要多用户并发请求数据。
解决:
使用分布式并发执行测试用例。分布式插件:pytest-xdist
安装及运行:pip install pytest-xdist
注意: 用例多的时候效果明显,多进程并发执行,同时支持 allure
可以看到,最终运行时间只需要6s,我的电脑是真6核,假12核
-n auto:可以自动检测到系统的CPU核数;从测试结果来看,检测到的是逻辑处理器的数量,即假12核
使用auto等于利用了所有CPU来跑用例,此时CPU占用率会特别高
pytest_addoption : 添加命令行参数,运时会先读取命令行参数
pytest_collection_modifyitems : 收集测试用例,收集之后(改编码,改执行顺序)
pytest_collection_finish:收集之后的操作
pytest_runtest_setup:在调用 pytest_runtest_call 之前调用
pytest_runtest_call:调用执行测试的用例
pytest_runtest_makereport:运行测试用例,返回setup,call,teardown的执行结果
def pytest_runtest_setup(item):
# 执行测试用例前执行的setup方法
print("setting up", item)
def pytest_runtest_call(item):
# 调用执行测试的用例
print("pytest_runtest_call")
def pytest_runtest_teardown(item):
# 执行测试用例后执行的teardown
print("pytest runtest teardown",item)
pytest_collection_modifyitems 收集上来的测试用例实现定制化功能
解决问题:
在conftest.py文件中加入以下代码:
含有中文的测试用例名称,改写编码格式:
def pytest_collection_modifyitems(session, config, items):
for item in items:
item.name = item.name.encode('utf-8').decode('unicode-escape')
item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')
def pytest_addoption(parser):
mygroup = parser.getgroup("hogwarts") #group 将下面所有的 option都展示在这个group下。
mygroup.addoption("--env", #注册一个命令行选项
default='test', # 参数的默认值
dest='env', # 存储的变量,为属性命令,可以使用Option对象访问到这个值,暂用不到
help='set your run env' # 帮助提示 参数的描述信息
)
@pytest.fixture(scope='session')
def cmdoption(request):
return request.config.getoption("--env")
构建文件 setup.py 代码路径:
https://ceshiren.com/t/topic/14156
from setuptools import setup,find_packages
setup(
name='pytest_encode',
url='https://github.com/xxx/pytest-encode',
version='1.0',
author="xixi",
author_email='[email protected]',
description='set your encoding and logger',
long_description='Show Chinese for your mark.parametrize(). Define logger variable for getting your log',
classifiers=[# 分类索引 ,pip 对所属包的分类
'Framework :: Pytest',
'Programming Language :: Python',
'Topic :: Software Development :: Testing',
'Programming Language :: Python :: 3.8',
],
license='proprietary',
packages = find_packages(), #['pytest_encode'],
keywords=[
'pytest', 'py.test', 'pytest_encode',
],
# 需要安装的依赖
install_requires=[
'pytest'
],
# 入口模块 或者入口函数
entry_points={
'pytest11': [
'pytest_encode = pytest_encode.main',
]
},
zip_safe=False
)
依赖包安装:
pip install setuptools python 的包管理工具,负责 安装和发布,尤其是安装拥有信赖关系的包。
pip install wheel 生成 *.whl 格式的安装包,本质上也是一个压缩包
打包命令:
python setup.py sdist bdist_wheel
python3 -m pip install --user --upgrade twine ## 安装 twine 工具
python3 -m twine upload --repository testpypi dist/* ## 上传代码
最后:下面是配套学习资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!【100%无套路免费领取】
被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!
涵盖以下这些面试题板块:
1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux
6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础