pytest_02
9-参数化parametrize
重要)
pytest.mark.parametrize装饰器可以实现测试用例参数化。
参数是列表,包含了元祖,然后每个元祖包含的是一组参数,然后,代码逻辑再处理根据传参进行逻辑处理
2.它也可以标记单个测试实例在参数化,例如使用内置的mark.xfail
# content of test_expectation.py
import pytest
@pytest.mark.parametrize("test_input,expected", [
("3+5", 8),
("2+4", 6),
pytest.param("6 * 9", 42, marks=pytest.mark.xfail),
])
def test_eval(test_input, expected):
print("-------开始用例------")
assert eval(test_input) == expected
if __name__ == "__main__":
pytest.main(["-s", "test_canshu1.py"])
pytest增加多个参数
适用场景 切换环境
import pytest
def pytest_addoption(parser):
parser.addoption("--input1",default="default input1")
parser.addoption("--input2",default="default input2")
@pytest.fixture
def input1(request):
return request.config.getoption("--input1")
@pytest.fixture
def input2(request):
return request.config.getoption("--input2")
----------------------
test1.py
import pytest
@pytest.mark.unit
def test_print_name(input1,input2):
print ("Displaying input1: %s" % input1)
print("Displaying input2: %s" % input2)
pytest执行方式
py.test -s test.py --input1 tt --input2 12
pytest-html生成html报告
pip install pytest-html
指定报告路径
1.直接执行"pytest --html=report.html"生成的报告会在当前脚本的同一路径,如果想指定报告的存放位置,放到当前脚本的同一目录下的report文件夹里
pytest --html=./report/report.html
2
报告独立显示
1.上面方法生成的报告,css是独立的,分享报告的时候样式会丢失,为了更好的分享发邮件展示报告,可以把css样式合并到html里;单独html报告
pytest --html=report.html --self-contained-html
失败重试
失败重跑需要依赖pytest-rerunfailures插件,使用pip安装就行
$ pip install pytest-rerunfailures
用例失败再重跑1次,命令行加个参数--reruns就行了
$ py.test --reruns 1 --html=report.html --self-contained-html
关于reruns参数的2个用法
re-run failing tests to eliminate flaky failures:
--reruns=RERUNS number of times to re-run failed tests. defaults to 0.
--reruns-delay=RERUNS_DELAY
add time (seconds) delay between reruns.
pytest 重试机制
第一种:对所有用例使用1、安装:pip install pytest-rerunfailures
2、命令行参数:pytest -- reruns 重试次数 (--reruns-delay 次数之间间隔)
pytest --reruns 2 运行失败的用例可以执行2次
pytest --reruns 2 --reruns-delay 5 运行失败的用例可以执行2次,每次间隔5秒
pytest.main(["-v","-m","demo","--reruns","2","--reruns-delay","5","--alluredir=../OutPuts/allure-results"])
pytest中的失败截图。
第二种:只对部分用例使用重运行机制在指定的用例使用装饰器,# 通常用上面的
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_example():
import random
assert random.choice([True, False])
pytest文档10-命令行传参
带参数启动
1.如果不带参数执行,那么传默认的default="type1",接下来在命令行带上参数去执行
命令行参数是根据命令行选项将不同的值传递给测试函数,比如平常在cmd执行"pytest --html=report.html",这里面的”--html=report.html“就是从命令行传入的参数
对应的参数名称是html,参数值是report.html
conftest配置参数
1.首先需要在conftest.py添加命令行选项,命令行传入参数”--cmdopt“, 用例如果需要用到从命令行传入的参数,就调用cmdopt函数:
# content of conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption(
"--cmdopt", action="store", default="type1", help="my option: type1 or type2"
)
@pytest.fixture
def cmdopt(request):
return request.config.getoption("--cmdopt")
2.测试用例编写案例
# content of test_sample.py
import pytest
def test_answer(cmdopt):
if cmdopt == "type1":
print("first")
elif cmdopt == "type2":
print("second")
assert 0 # to see what was printed
if __name__ == "__main__":
pytest.main(["-s", "test_case1.py"])
cmd打开,输入指令启动,也可以在pycharm里面右键执行上面代码
$ pytest -s test_sample.py
带参数启动
1.如果不带参数执行,那么传默认的default="type1",接下来在命令行带上参数去执行
$ pytest -s test_sample.py --cmdopt=type2
2.命令行传参数有两种写法,还有一种分成2个参数也可以的,参数和名称用空格隔开
$ pytest -s test_case1.py --cmdopt type2
pytest文档11-assert断言
断言是写自动化测试基本最重要的一步,一个用例没有断言,就失去了自动化测试的意义了。什么是断言呢?
简单来讲就是实际结果和期望结果去对比,符合预期那就测试pass,不符合预期那就测试 faile
异常断言
为了写关于引发异常的断言,可以使用pytest.raises作为上下文管理器,如下
# content of test_assert1.py
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
运行结果
============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: D:\YOYO\canshuhua, inifile:
plugins: metadata-1.7.0, html-1.19.0
collected 1 item
test_assert1.py.
========================== 1 passed in 0.31 seconds ===========================
如果我们要断言它抛的异常是不是预期的,比如执行:1/0,预期结果是抛异常:ZeroDivisionError: division by zero,那我们要断言这个异常,通常是断言异常的type和value值了。
这里1/0的异常类型是ZeroDivisionError,异常的value值是division by zero,于是用例可以这样设计
常用断言
pytest里面断言实际上就是python里面的assert断言方法,常用的有以下几种
- assert xx 判断xx为真
- assert not xx 判断xx不为真
- assert a in b 判断b包含a
- assert a == b 判断a等于b
- assert a != b 判断a不等于b
pytest文档14-函数传参和fixture传参数request
暂时没用到
登录函数传参
把登录单独出来,写一个函数,传2个参数user和psw,写用例的时候调用登录函数,输入几组user,psw参数化登录用例
测试用例传参需要用装饰器@pytest.mark.parametrize,里面写两个参数
- 第一个参数是字符串,多个参数中间用逗号隔开
- 第二个参数是list,多组数据用元祖类型
import pytest
# 测试登录数据
class sk(object):
def login(self,user, psw):
'''普通登录函数'''
print("登录账户:%s"%user)
print("登录密码:%s"%psw)
if psw:
return True
else:
return False
class Test_sk(object):
ks_sk=sk()
test_login_data = [("admin", "111111"), ("admin", "222222")]
@pytest.mark.parametrize("user, psw", test_login_data)
def test_login(self,user, psw):
'''登录用例'''
result = self.ks_sk.login(user, psw)
assert result == True, "失败原因:密码为空"
request参数
如果想把登录操作放到前置操作里,也就是用到@pytest.fixture装饰器,传参就用默认的request参数
user = request.param 这一步是接收传入的参数,本案例是传一个参数情况
添加indirect=True参数是为了把login当成一个函数去执行,而不是一个参数
request传2个参数
如果用到@pytest.fixture,里面用2个参数情况,可以把多个参数用一个字典去存储,这样最终还是只传一个参数
不同的参数再从字典里面取对应key值就行,如: user = request.param["user"]
# test_03.py
# coding:utf-8
import pytest
# ** 作者:上海-悠悠 QQ交流群:588402570**
# 测试账号数据
test_user_data = [{"user": "admin1", "psw": "111111"},
{"user": "admin1", "psw": ""}]
@pytest.fixture(scope="module")
def login(request):
user = request.param["user"]
psw = request.param["psw"]
print("登录账户:%s" % user)
print("登录密码:%s" % psw)
if psw:
return True
else:
return False
# indirect=True 声明login是个函数
@pytest.mark.parametrize("login", test_user_data, indirect=True)
def test_login(login):
'''登录用例'''
a = login
print("测试用例中login的返回值:%s" % a)
assert a, "失败原因:密码为空"
if __name__ == "__main__":
pytest.main(["-s", "test_03.py"])