pytest是一个使构建简单和可扩展测试变得容易的框架。
命名
文件名必须是test_开头 或_test结尾的.py文件
类名必须是Test开头
测试函数以test_开头;_test结尾不可以(如b_test());
文件夹(包名)名可以随意命名
cmd下执行测试
1.执行当前cmd所在目录下的所有用例 #默认执行文件名为test_*.py或*_test.py的文件
pytest 或py.test 或python -m pytest
2.执行某一个py文件下的用例
pytest test_1.py
pytest -q test_1.py #输出保持简短,只显示结果
pytest -s #显示用例的打印信息
3.按节点运行
运行.py模块里面的某个函数 pyest 脚本名::函数名,如pytest test_a.py::test_1
运行.py模块里面,测试类里面的某个方法 pytest 脚本名::类名::方法名,如pytest b_test.py::Testa::test_2
4.-x 遇到错误时停止测试
pytest -x test_a.py
5.--maxfail=num
当用例错误个数达到指定数量num时,停止测试
6.执行上次失败用例
--lf last-failed (包含failed和error用例)
--ff failed-first
pytest -s --lf
pytest -s --ff (先运行上次失败的,后运行其他通过的用例)
7.重复执行用例(pytest-repeat)
pytest -s --count=5 (当前文件夹下,所有测试用例重复执行5次,一个用例执行5次后,再执行另一个用例5次)
pytest -s --count=3 --repeat-scope=session #所有用例执行1次后,再执行1次,再执行一次
repeat-scope也可以=function(默认),class,module
针对某个测试用例重复多次,可以加装饰器@pytest.mark.repeat(5)
--count是针对无装饰器的重复
重复测试直至失败
pytest --count=n -x test_1.py,尝试运行test-1.pyn次,一旦发生失败,就停止
pycharm执行pytest用例
设置默认测试执行器为pytest
前置setup、后置teardown操作(对整个脚本,全局生效)
函数式(类外):setup_function(), teardown_function()
def setup_function():
print("每个用例开始前都会执行")
.py模块级:setup_module(),teardown_module()
def teardown_module():
print("所有用例结束后,关闭浏览器")
类里或类外,setup(), teardown(),每个方法/函数用例前后执行;
类里:setup_class(),teardown_class();类中,用例执行前后一次;
类里:setup_method(),teardown_method();类中,每个用例前后执行;
注意:类里的前置、后置操作定义在类外,不报错,也不会执行
函数的前置、后置操作定义在类里,不报错,也不会执行
小结:setup_function(),setup(),setup_method(),都是每个用例前执行一次;但作用域有区别,setup_function()只在类外,对每个函数用例起作用
setup(),可以在类外、类里对每个用例起作用;
setup_method()只在类里,对每个方法用例起作用;
所以后面需要对每个用例起作用,直接使用setup(), teardown()
fixture介绍
定义fixture跟普通函数的区别就是在函数上加个装饰器@pytest.fixture(),fixture的函数名不要以test_开头。
fixture可以有返回值的。如果没return,默认返回None。用例调用fixture的返回值,直接就是把fixture的函数名称当成变量名称。
fixture可以return一个元组、list或字典,然后从里面取出对应数据;
可以分开定义多个fixture,然后test_用例传多个fixture参数;
fixture与fixture互相调用,一个fixture下的函数传另一个fixture参数;
fixture作用范围
session > module > class > function(默认)
- function每一个函数或方法都会调用
- class每一个类调用一次
- module 每一个.py文件调用一次
- session 是多个文件调用一次,可以跨.py文件调用
conftest.py
可以有多个,当前所在目录及以下目录生效
配置fixture
fixture 自定义测试用例前置条件
@pytest.fixture()
def login():
print("我是登录哦")
def test_1(login): #调用时,写上函数名就行;此时会先执行login(),然后执行test_1()
print("我是用例")
如果多个.py文件,多个用例调用登录功能,可以将登录写到新建的conftest.py中
@pytest.fixture()
def login():
print("我是登录哦")
fixture里面的yield唤醒后置操作的执行
conftest.py中写入:
@pytest.fixture(scope="module") #scope默认值是“function”
def open():
print("打开浏览器")
yield
print("关闭浏览器")
fixture之autouse=True
import pytest @pytest.fixture(autouse=True)#可设置scope参数 def browser(): print("打开UC") yield print("关闭UC") def test_1(): print("我是test1") def test_2(): print("我是test2") if __name__=="__main__": pytest.main(["-s","test_a.py"])
pytest-html生成html报告
cmd下执行,pytest --html=E:\报告名.html --self-contained-html
测试用例参数化parametrize
@pytest.mark.parametrize("参数a,参数b",[("值1","值2"),("值3","值4")]) #@pytest.mark.parametrize("参数a",["值1","aa"])#第一个参数是字符串,多个参数中间用逗号隔开 #@pytest.mark.parametrize("参数b",["值11","bb"])#第2个参数是list,多组数据用元组类型, def test_1(参数a,参数b): print(参数a,参数b)
注意:值的格式不同,最终使用时,组合的情况不同
命令行传参
pytest --html=report.html就是命令行传参,参数名称是html,参数值是report.html
函数传参、request参数
#方式1
test_data=[("v1","v2"),("v3","v4)]
def login(p1,p2):
print(p1,p2)
@pytest.mark.parametrize("name,pwd",test_data)
def test_a(name,pwd):#测试用例
login(name,pwd)
#方式2
##传1个参数
import pytest est_data=["v1","v2"] data=["v3"] @pytest.fixture() def login(request): user=request.param #接收传入的传参 print("user={}".format(user)) return user @pytest.mark.parametrize("login",data,indirect=True) #把login当成一个函数,第2个是参数名 def test_a(login):#测试用例 a=login print("a={}".format(a)) if __name__=="__main__": pytest.main(["-s","test_a.py"])
##传2个参数,列表里可以嵌套各种数据元组,字典,列表;
未截图部分,与上面的代码一致;
fixture参数化params
fixture有几个参数:scope,params,autouse,ids,name
获取当前参数可以使用request.param
import pytest d=["ad","te"] @pytest.fixture(params=d) def user(request): return request.param def test_a(user): print(user)
登录用例失败,跳过需登录的用例,并标记失败xfail
将登录放到前置操作中(@pytest.fixture),返回True 、False
def login():
data=
使用request传参,@pytest.mark.parametrize("login",data,indirect=True):
def test_a(login):#用例
r=login
assert r==True 或 if not r:pytest.xfail("r为假,就是xfail")
注意:assert r,r为假时,结果是failed
使用了pytest.xfail(),r为假时,结果是xfailed
pytest.ini
新建一个pytest.ini文件
#pytest.ini [pytest] markers= banner: banner ppny: 我是备注,随意写
mark标记
cmd下运行pytest -v -m=banner
注意:mark下面是函数,则只影响该函数;mark下面是类,则影响该类下的所有用例
addopts 修改参数
#pytest.ini [pytest] markers= banner: banner ppny: 我是备注,随意写 addopts=-v -m=ppny --html=report.html --self-contained-html
cmd下运行pytest,就可以执行标记为ppny部分的代码,且会生成报告
pytest.ini配置用例查找规则
如下,pytest 则会执行c_*.py文件
[pytest] python_files=c_*.py
python_classes = Test*
python_functions=test_*
pytest插件
@pytest.mark.run(order=1) #改变测试用例执行顺序
allure-pytest
@allure.epic("描述") #epic描述
@allure.feature("描述") #模块描述
@allure.story("描述") #用户故事
@allure.title("描述") #用例的标题
@allure.testcase("描述") #测试用例的链接地址
@allure.issue("描述") #缺陷
@allure.description("描述") #用例描述
@allure.step("描述用例步骤") #操作步骤
@allure.serverity("blocker") #用例等级,blocker,critical,normal(默认),minor,trivial
@allure.link("内容") #链接
#@allure.attachment("描述") #附件
执行用例 pytest --alluredir ./report/allure_raw #注意:./report/allure_raw 为报告路径+名,可随意命名
打开html报告 allure serve report/allure_raw
import allure @allure.epic("学习allure使用") @allure.feature("我是feature") @allure.story("学pytest有半个月了,正在小结中,然后就是在项目种使用了") class Testc: @allure.title("登录用例") @allure.issue("https://www.bug.cn") @allure.testcase("https://www.baidu.com") @allure.step("输入账号") def test_login(self): print("登录成功") @allure.description("我是test_2的用例描述") def test_2(self): print("feature部分") @allure.link("https://www.sogou.com/") def test_3(self): print("story部分") @allure.severity("blocker") def test_4(self): print("blocker部分")
备注:1.可以在某个函数或类上添加多个allure描述;
2.epic描述、模块名称、用户故事、用例标题会展示在左边;测试用例的链接地址、缺陷、链接会展示在右边链接中;用例描述、操作步骤、用例等级会展示在右边;
断言
自动化测试最重要的一步。实际结果和期望结果去对比,符合预期测试就pass,反之failed
assert xx assert no xx assert a in b assert a==b assert a!=b
结果
error:fixture断言失败,用例使用了fixture,则为error;若用例本身错误,也是error;
failed:用例断言失败,则是failed;