陆陆续续断更好久好久了,这么久发生了很多事情,也思考了很多事情。突然发现拖延症已经严重影响到了我。
什么是拖延症,简单来说就是个人选择而已。每时每刻,面临辛苦的选项与逃避的选项时,倾向于选择更安逸的那一个。一而再再而三,就成了拖延。很早之前我就计划专注某个方面写一个系列,但是直到今日,仍没有结果,实在是有些惭愧,想从新逼迫自己进步,不知道能坚持多久。
言归正传,谈下pytest,很多人会有疑问,网上都那么多pytest文章了,为什么我还要专门写呢,其实很简单。原因有二,第一个就是老生常谈的话题了多数人写技术博客都是通过写来看自己掌握的进度,同时哪天有用到了,回过头看,也可以起到温故而知新的作用。第二,刚好有测试妹子给我提供了一些简单的pytest的小案例,我也正有此意,那这篇文章就这样来了。
先声明:我写的技术文主要还是以理解为主,不一定专业,如果看完还是不会,那一定是我写的不够好。不要因为我写的太过于乏味而打消自己学习的念头。
回到正文pytest
,可能很多常写python
的人第一次听到这个库,它究竟有什么用呢?
pytest 是一个成熟的全功能的 Python 测试工具。这里提供一份Pytest 使用手册以及官方文档。
selenium/appnium
等自动化测试、接口自动化测试(pytest
+requests
);pytest
具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium
(集成selenium)、pytest-html
(完美html测试报告生成)、pytest-rerunfailures
(失败case重复执行)、pytest-xdist
(多CPU分发)等;skip
和xfail
处理;jenkins
等等;pip install -U pytest
pytest --version # 会展示当前已安装版本
pytest
中,assert
是编写测试的最基础工具。如:a = 1
b = 3
assert a == b
执行结果
Traceback (most recent call last):
File "/home/xsl/test.py", line 3, in <module>
assert a == b
AssertionError
默认情况下,pytest
会递归查找当前目录下所有以 test
开始或结尾的 Python
脚本,并执行文件内的所有以 test
开始或结束的函数和方法。
# test_no_mark.py
def test_func1():
assert 1 == 1
def test_func2():
assert 1 != 1
所以,编写pytest
测试样例非常简单,只需要按照下面的规则:
test_
开头(以_test
结尾也可以)Test
开头,并且不能带有 init
方法(注意:定义class时,需要以T开头,不然pytest是不会去运行该class的)test_
开头import pytest
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
if __name__ == '__main__':
pytest.main("-s test.py")
执行测试代码结果如下,pytest将显示错误信息,因为func(3)未返回5:
============================= test session starts ==============================
platform linux -- Python 3.5.3, pytest-3.4.1, py-1.5.2, pluggy-0.6.0
rootdir: /home/xsl, inifile:
collected 1 item
test.py F
=================================== FAILURES ===================================
_________________________________ test_answer __________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test.py:15: AssertionError
=============================== warnings summary ===============================
None
passing a string to pytest.main() is deprecated, pass a list of arguments instead.
-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 1 failed, 1 warnings in 0.10 seconds =====================
@pytest.mark.parametrize
,那我们就详细讲解下pytest.mark.parametrize使用方法:@pytest.mark.parametrize('参数',list)
参数一是字符串,多个参数中间用逗号隔开 第二个参数是list,多组数据用元祖类型;list的每个元素都是一个元组,元组里的每个元素和按参数顺序一一对应
# 一个参数
@pytest.mark.parametrize('参数名',list) 进行参数化
# 两个参数
@pytest.mark.parametrize('参数名1,参数名2',[(参数1_data[0], 参数2_data[0]), (参数1_data[1], 参数2_data[1])])
import pytest
data =[[1,1], [2,1+1], [6,2*3],]
@pytest.mark.parametrize('a, b', data)
def test_assert(a, b):
assert a == b
if __name__ == '__main__':
pytest.main('-q test.py')
执行结果
... [100%]
=============================== warnings summary ===============================
None
passing a string to pytest.main() is deprecated, pass a list of arguments instead.
-- Docs: http://doc.pytest.org/en/latest/warnings.html
3 passed, 1 warnings in 0.01 seconds
import pytest
@pytest.mark.parametrize("user_nm, pass_wd",
[("xu", "123456"), ("ni", "123456"),
("xing", "123456"), ("chen", "123456")])
def test_login(user_nm, pass_wd):
print(user_nm + " : " + pass_wd)
assert pass_wd == '123456'
if __name__ == '__main__':
pytest.main('-s test.py')
执行结果如下:
============================= test session starts ==============================
platform linux -- Python 3.5.3, pytest-3.4.1, py-1.5.2, pluggy-0.6.0
rootdir: /home/xsl/gogs/dps/etl, inifile:
collected 4 items
test.py xu : 123456
.ni : 123456
.xing : 123456
.chen : 123456
.
=============================== warnings summary ===============================
None
passing a string to pytest.main() is deprecated, pass a list of arguments instead.
-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 4 passed, 1 warnings in 0.01 seconds =====================
细心的朋友发现了,每次我执行的时候会用pytest.main('-s 文件名')
其实这里的-s是可以根据不同的需求进行替换的,这里我们替换成-v,那么执行结果就变成了
============================= test session starts ==============================
platform linux -- Python 3.5.3, pytest-3.4.1, py-1.5.2, pluggy-0.6.0 -- /usr/bin/python3.5
cachedir: .pytest_cache
rootdir: /home/xsl, inifile:
collecting ... collected 4 items
test.py::test_login[xu-123456] PASSED [ 25%]
test.py::test_login[ni-123456] PASSED [ 50%]
test.py::test_login[xing-123456] PASSED [ 75%]
test.py::test_login[chen-123456] PASSED [100%]
=============================== warnings summary ===============================
None
passing a string to pytest.main() is deprecated, pass a list of arguments instead.
-- Docs: http://doc.pytest.org/en/latest/warnings.html
===================== 4 passed, 1 warnings in 0.01 seconds =====================
这样就可以写很多个测试文件,然后在另外的文件中使用pytest.main('-s 文件名')
去执行,又因为前文讲了,pytest
会递归查找当前目录下所有以 test 开始或结尾的 Python 脚本,并执行文件内的所有以 test开始或结束的函数和方法。所以当需要测试的文件特别多,就可以直接另写一个文件
import pytest
if __name__ == '__main__':
pytest.main('-s test.py')
其实根据自己不同的需求来确定pytest.main('')
括号内的内容,比如
./
目录下所有(test_*.py
和 *_test.py
)pytest.main(['./'])
./xdj
目录下的所有用例pytest.main (['./xdj'])
pytest.main (['./xdj/test01.py'])
test01.py
中的test_login
方法pytest.main (['./xdj/test01.py::test_login'])
test02.py
中test2
(类)的方法test_class
pytest.main (['./xdj/test02.py::test2::test_class'])
love
的用例(匹配目录名、模块名、类名、用例名)pytest.main (['-k','love'])
test.py
模块下包含hello
的用例pytest.main(['-k','hello','./xdj/test.py'])