Menu: python pytest测试实战 1
Pycharm如何将本地文件提交到远程github仓库
1.本地建立好待上传文件夹,如果全是空文件夹将会被忽略,一般新项目都会创建个README.MD文件,里面放着项目的介绍信息
2.远程仓库创建对应的repositories
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/Clearbit-Rickey/HogwartsSDET.git
git push -u origin main
3.在待上传文件夹路径,执行git init,此时Pycharm右上角会出现对勾,点击对勾,将不需要加入仓库的文件添加到gitignore文件上
4.选择需要上传到github的文件,右侧Before Commit选择Reformat code,填写commit信息,点击commit
#第三步和第四步勾选对勾的意思实际上执行了俩个命令git add 和 git commit
5.此时运行git remote add origin https://github.com/Clearbit-Rickey/HogwartsSDET.git 和远程仓库关联
6.运行git push -u origin main #push到远程仓库
#git branch #查看当前所在分支,如果在master分支需要切换为本地分支
#git checkout 分支名 #切换分支,切换到所需要使用的分支名称
#git checkout --xxx #丢掉工作区的内容
pytest 介绍与安装
pip install pytest
pytest 常用执行参数
python sys.path.append('..') #'..'代表sys.path追加上一级目录
#'../..'代表sys.path追加上上级目录
常用参数
pytest --collect-only 只收集用例
pytest -k “add ” 匹配所有名称中包含add的用例(‘add or div’ ‘TestClass’)
pytest -m mark标签名 标记
pytest - - junitxml=./result.xml 生成执行结果文件
pytest --setup-show 回溯fixture的执行过程
更多的用法使用pytest —help查看帮助文档
pytest 框架结构
import pytest 类似的setup,teardown同样更灵活,
模块级(setup_module/teardown_module)模块始末,全局的( 优先最高 )
函数级(setup_function/teardown_function)只对函数用例生效(不在类中)
类级 (setup_class/teardown_class) 只在类中前后运行一次(在类中)
方法级(setup_method/teardown_methond)开始于方法始末(在类中)
类里面的( setup/teardown ) 运行在调用方法的前后
#函数级别 类外面使用def定义的叫做函数
#在类里面使用def定义的叫方法
#模块级别、函数级别、类级别、方法级别
#测试文件
from pythoncode.calc import Calculator
# 模块级别
def setup_module():
print("模块级别setup")
def teardown_module():
print("模块级别teardown")
# 函数级别 类外面的使用def 定义的叫做函数,
# 在类里面使用def 定义的叫方法
def setup_function():
print("函数级别 setup")
def teardown_function():
print("函数级别 teardown")
def test_add2(): #执行这段代码会走模块级别和函数级别,这段代码不在类中
calc2 = Calculator()
assert 5 == calc2.add(1,4)
class TestCalc:
# setup_class, teardown_class每个类里面 执行前后分别 执行
def setup_class(self):
self.cal = Calculator()
print("类级别 setup")
def teardown_class(self):
print("类级别 teardown")
# 方法级别 每条类里面的测试用例前和后分别 执行setup teardown
def setup(self):
print("setup")
def teardown(self):
print("teardown")
def test_add(self): #执行这段代码会走类里面的方法级别,会执行模块级别、类级别、方法级别
# cal = Calculator()
assert 3 == self.cal.add(1, 2)
# #执行结果为:
# 模块级别setup
# 函数级别 setup
# .函数级别 teardown
# 类级别 setup
# setup
# .teardown
# 类级别 teardown
# 模块级别teardown
pytest 参数化
参数化装饰函数
ids参数增加可读性
# ids参数增加可读性
@pytest.mark.parametrize('a,b,result',
[[1, 2, 3],
[2, 4, 6],
[100, 200, 300],
[0.2, 0.3, 0.5],
[-1, -2, -3]],ids=['int1','int2','bigint','float','负数'])
#ids参数增加可读性,给测试的数据取别名,别名也可以在allure中进行展示
def test_add(self, a, b, result):
assert result == self.cal.add(a, b)
pytest fixture
1、对于setup,teardown,可以不起这两个名字, 命名方式灵活。(可独立命名,声明后激活)
2、数据共享。在conftest.py配置里写方法可以实现数据共享,不需要import导入。可以跨文件共享
3、scope的层次及神奇的yield组合相当于各种setup 和 teardown
pytest fixture 应用
#pytest fixture 应用
import pytest
@pytest.fixture()
def login():
print("登录方法")
#没写返回值时,默认返回值为NOne
#yield 生成器
# yield 激活fixture teardown方法
yield ['username','password'] #相当于返回,也可以带返回值
print("teardown")
#测试用例执行之前先执行login方法
def test_case1(login):
print(f"case1 login = {login}")
def test_case2(): #case2未调用登录方法,不走teardown方法
print("case2")
def test_case3(login):
print(f"case3 login = {login}")
#pytest --setup-show test_login.py #在命令行输入查看test_login.py模块,回溯fixture执行过程
#可以看到运行test_login.py文件执行了teardown方法
#执行结果为:
登录方法
case1 login = ['username', 'password']
teardown
case2
登录方法
case3 login = ['username', 'password']
teardown
yield生成器
#yield生成器
def func():
for i in range(3):
print(f'i={i}')
# 大量数据,如果每次读取加载到列表会卡死,可以使用yield生成器,每次读取一条
yield #相当于return 同时相当于暂停并且记住上一次的执行位置
### 上面的例子可以看出 yield 激活 fixture teardown方法
print("end")
#注意使用python解释器运行
f = func() # f就是生成器
next(f) # next(f)获取生成器下一个值
next(f)
next(f)
执行结果为:
i=0
end
i=1
end
i=2
自动化中的应用2 conftest.pytest
场景:
你与其他测试工程师合作一起开发时,公共的模块要在不同文件中,要在大家都访问到的地方
解决:
使用conftest.py这个文件进行数据共享,并且它可以放在不同位置起着不同的范围共享作用
前提:
conftest文件名是不能换的,放在项目下是全局的数据共享的地方,全局的配置和前期工作
都可在某个包下,就是这个包数据共享的地方
执行:
系统执行到参数login时先从本文件中查找是否有这个名字的变量什么的,之后在conftest.py中查找
先从本文件中查找是否有这个名字的变量,然后查找同级目录下的conftest.py文件,优先执行同级目录下的conftest.py的方法和规则,然后执行现有模块的方法
现有模块不需要导入conftest.py定义的方法,可以直接进行调用
步骤:
将登录模块带@pytest.fixture写在conftest.py
#conftest.py配置里写方法可以实现数据共享
#conftest.py文件内容如下:
import pytest
#将登录模块带@pytest.fixture写在conftest.py
@pytest.fixture()
def login():
print("登录方法")
#没写返回值时,默认返回值为NOne
#yield 生成器
# yield 激活fixture teardown方法
yield ['username','password'] #相当于返回,也可以带返回值
print("teardown")
#test_login.py文件内容如下:
#现有模块不需要导入conftest.py定义的方法,可以直接进行调用
#测试用例执行之前先执行login方法
def test_case1(login):
print(f"case1 login = {login}")
def test_case2():
print("case2")
def test_case3(login):
print(f"case3 login = {login}")
#test_login.py文件执行结果为:
登录方法
case1 login = ['username', 'password']
teardown
case2
登录方法
case3 login = ['username', 'password']
teardown
scope的层次 @pytest.fixture(scope='session')
scope='session'
#one of ``"function"``
# (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``. #scope的几种参数
session整个项目只执行一次,module每个模块,也就是每个.py文件只执行一次
自动化中的应用5
场景:测试离不开数据,为了数据灵活,一般数据都是通过参数传的
解决:fixture 通过固定参数request传递
步骤:
在fixture中增加@pytest.fixture(params=[1,2,3,'linda'])
在方法参数写request,方法体里面使用request.param接收参数
#conftest.py文件内容如下:
import pytest
@pytest.fixture(params=['user1','user2','user3'])
def login(request): #在方法参数写request
print("登录方法")
print(request.param) #方法体里面使用request.param接收参数
#没写返回值时,默认返回值为NOne
#yield 生成器
# yield 激活fixture teardown方法
yield ['username','password'] #相当于返回,也可以带返回值
print("teardown")
#test_login.py文件内容如下:
#测试用例执行之前先执行login方法
def test_case1(login):
print(f"case1 login = {login}")
#test_login.py文件执行结果为:
登录方法
user1
case1 login = ['username', 'password']
teardown
登录方法
user2
case1 login = ['username', 'password']
teardown
登录方法
user3
case1 login = ['username', 'password']
给fixture方法参数化
场景:比如想使用不同的用户登录进行购物车功能
indirect 默认为False,传入参数的值。如果设定为True,就可以传入方法的名字
方法接收方法名字
数据传入到方法体里面
#conftest.py文件内容如下:
import pytest
@pytest.fixture()
def login(request): #在方法参数写request
print("登录方法")
print(request.param) #方法体里面使用request.param接收参数
print("teardown")
#test_cart.py文件内容如下:
import pytest
#给fixture方法参数化啦
'''
#给fixture方法参数化啦
传入一个fixture方法,将数据传入到fixture方法中,fixture方法使用request参数来接收这组数据,
在方法体里面使用request.param 来使用这个数据
'''
@pytest.mark.parametrize('a,b',[ #使用多个@pytest.mark.parametrize时为迭代传参
(1,2),
(3,4)
])
@pytest.mark.parametrize('login',[ #fixture方法参数化一定要使用定义的方法名称,该例子login方法定义在conftest.py文件中
('username1','password1'), #数据传入到方法体里面
('username2','password2')
],indirect=True) #indirect 默认为false,传入参数的值。如果设定为true,就可以传入方法的名字
def test_cart1(login,a,b): #方法接收方法名字
print("购物车功能")
#test_cart.py文件执行标题为:
test_cart1
(login0-1-2) #login0为方法传参 1、2为参数传参
(login0-3-4)
(login1-1-2)
(login1-3-4)
#test_cart.py文件执行结果为:
登录方法
('username1', 'password1')
teardown
PASSED [ 25%]购物车功能
登录方法
('username1', 'password1')
teardown
PASSED [ 50%]购物车功能
登录方法
('username2', 'password2')
teardown
PASSED [ 75%]购物车功能
登录方法
('username2', 'password2')
teardown
PASSED [100%]购物车功能