一、框架介绍及安装
框架介绍
pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。
安装
pip安装:pip install pytest
二、框架使用流程
快速使用
1.准备源码文件test.py。
2.cmd中切换至源文件所在目录。
3.运行pytest命令,
或py.test命令,
或python –m pytest命令。
pytest运行规则
- 查找当前目录及其子目录下以test_*.py或*_test.py文件。
- 找到文件后,在文件中找到以test开头函数并执行。
运行测试类
- 多条用例时,需要建立测试类
- 多个测试模块时,可以选择执行部分模块用例。
- py.test -q test_two.py
用例设计原则
- 文件名以test_*.py文件*_test.py
- 测试类以Test开头,并且不能带有init方法
- 以test_开头的函数
- 以Test开头的类
- 以test_开头的方法
- 所有的包pakege必须要有__init__.py文件
- 断言使用assert
执行用例规则
- 某个目录下所有的用例
pytest 目录名/
- 执行某一个py文件下用例
pytest脚本名称.py
- -k按关键字匹配
pytest -k "MyClass and not method“
- 按节点运行
来自参数化的类名,函数名为参数,由:: characters分隔。
运行.py模块里面的某个函数
>pytest test_mod.py::test_func
运行.py模块里面,测试类里面的某个方法
>pytest test_mod.py::TestClass::test_method
- 标记表达式
>pytest -m slow
将运行用@ pytest.mark.slow装饰器修饰的所有测试。后面章节会讲自定义标记mark的功能。
- 从包里面运行
>pytest --pyargs pkg.testing
返将导入pkg.testing并使用其文件系统位置来查找来运行测试。
命令参数
-q --quiet decrease verbosity(显示简单结果)
-x 遇到错误时停止测试
--maxfail=num
当用例错误个数达到指定数量时,停止测试
--help 帮助
三、Pycharm下运行pytest
以xx.py脚本方式直接执行
- 当写的代码里面没用到unittest和pytest框架时
- 并且脚本名称不是以test_开头命名的
- 此时pycharm会以xx.py脚本方式运行
当脚本命名为test_xx.py时
- 用到unittest框架,此时运行代码,pycharm会自动识别到以unittest方式运行
以pytest方式运行
- 需要改该工程设置默认的运行器
- file->Setting->Tools->Python Integrated Tools->项目名称->Default test runner->选择py.test
四、断言
定义:断言为实际结果和期望结果去对比,符合预期那就测试pass,不符合预期那就测试failed。
常用断言
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.mark.skip 可以标记无法在某些平台上运行的测试功能,或者希望失败的测试功能。
skip if意味着在不满足某些条件时才希望测试通过,否则 pytest应该跳过运行测试。 常见示例是在非 Windows 平台上跳过仅限Windows 的测试,或跳过 测试依赖于当前不可用的外部资源。
xfail 意味着你希望测试由于某种原因而失败。 一个常见的例子是对功能的测试尚未实施,或尚未修复的错误。
skip
跳过测试函数的最简单方法是使用跳过装饰器标记它,可以传递一个可选的原因。
@pytest.mark.skip(reason=“本轮测试不执行此用例")
skip
可以通过调用来在测试执行或设置期间强制跳过。
pytest.skip(reason)功能:
def test_function(): if not valid_config(): pytest.skip(“本用例跳过")
skipif
如果你希望有条件地跳过某些内容,则可以使用 skipif 代替。
import sys @pytest.mark.skipif(sys.version_info < (3,6),reason="requires python3.6 or higher")
skipif
可以在模块之间共享 skipif 标记。
对于较大的测试套件,通常最好有一个文件来定义标记,然后一致适用于整个测试套件。
minversion = pytest.mark.skipif(5>3,reason=“test") @minversion def test_function():
skip其它
可以在类上使用 skipif 标记。
如果要跳过模块的所有测试功能,可以在全局级别使用pytestmark名称:pytestmark = pytest.mark.skipif(...)
自定义标记 mark
pytest 可以支持自定义标记,自定义标记可以把一个 web 项目划分多个模块,然后指定模块名称执行。
@pytest.mark.webtest def test_send_http():
如果不想执行标记 webtest 的用例,那就用”not webtest”
六、Fixture
1、用例运行级别
- 模块级(setup_module/teardown_module)开始于模块始末,全局的
- 函数级(setup_function/teardown_function)只对函数用例生效(不在类中)
- 类级(setup_class/teardown_class)只在类中前后运行一次(在类中)
- 方法级(setup_method/teardown_method)开始于方法始末(在类中)
- 类里面的(setup/teardown)运行在调用方法的前后
2、运行的优先级
setup_class>setup_method>setup >用例>teardown> teardown_method>teardown_class
3、函数和类混合
- 如果一个.py 的文件里面既有函数用例又有类和方法用例,运行顺序如下:
- setup_module/teardown_module 的优先级是最大的。
- 函数里面用到的 setup_function/teardown_function和类里面的 setup_class/teardown_class 互不干涉
4、fixture 优势
- 相对于 setup 和teardown 来说有以下几点优势:
- 命名方式灵活,不限于 setup 和 teardown 这几个命名。
- conftest.py 配置里可以实现数据共享,不需要 import 就能自动找到一些配置。
- scope="module" 可以实现多个.py 跨文件共享前置
- scope=“session” 以实现多个.py 跨文件使用一个 session 来完成多个用例。
5、参数解析
- fixture(scope="function", params=None, autouse=False,ids=None, name=None):
- scope 有四个级别参数:function, class、Module、session
- params: 一个可选的参数列表,它将导致多个参数调用fixture 功能和所有测试使用它。
- fixture(scope="function", params=None, autouse=False,ids=None, name=None):
- autouse: 如果为 True,则为所有测试激活 fixture func 可以看到它。 如果为 False(默认值)则显式需要参考来激活 fixture
- fixture(scope="function", params=None, autouse=False,ids=None, name=None):
- 每个字符串 id 的列表,每个字符串对应于 params 这样他们就是测试 ID 的一部分。 如果没有提供 ID 它们将从 params 自动生成。
- fixture(scope="function", params=None, autouse=False,ids=None, name=None):
- name: fixture 的名称。 这默认为装饰函数的名称。
例:scope="function"
例:scope="module"
6、conftest.py 配置
- conftest.py 配置脚本名称是固定的,不能改名称
- conftest.py 和运行的用例要在同一个 pakage 下,并且有__init__.py 文件
- 不需要 import 导入 conftest.py, pytest 用例会自动查找
7、yield 执行 teardown
- yield:提供
- fixture 里面的 teardown 用 yield 来唤醒teardown的执行
import pytest @pytest.fixture(scope="module") def open(): print("打开浏览器,并且打开百度首页") yield print("执行 teardown!") print("最后关闭浏览器") def test_s1(open): print("用例 1:搜索 python-1") def test_s2(open): print("用例 2:搜索 python-2") if __name__ == "__main__": pytest.main()
yield 遇到异常
- 如果其中一个用例出现异常,不影响 yield 后面的 teardown 执行,运行结果互不影响,并且全部用例执行完成后, yield 呼唤 teardown操作。
- 如果在 setup 就异常了,那么是不会去执行 yield 后面的teardown 内容了。
- yield 也可以配合 with 语句使用。
8、参数化
parametrize
pytest.mark.parametrize 装饰器可以实现测试用例参数化。
import pytest @pytest.mark.parametrize("test_input,expected",[ ("3+5", 8),("2+4", 6),("6 * 9", 42),]) def test_eval(test_input, expected): assert eval(test_input) == expected
它也可以标记单个测试实例在参数化
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): assert eval(test_input) == expected
9、参数组合
import pytest @pytest.mark.parametrize("x", [0, 1]) @pytest.mark.parametrize("y", [2, 3]) def test_foo(x, y): print("测试数据组合: x->%s, y->%s" % (x, y)) if __name__ == "__main__": pytest.main()
10、HTML报告(pytest-html)
安装
pytest-HTML 是一个插件, pytest 用于生成测试结果的 HTML 报告。
pip 安装
> pip install pytest-html
执行方法
> pytest --html=report.html
此方法生成的报告, css 是独立的,分享报告的时候样式会丢失,为了更好的分享发邮件展示报告,可以把 css 样式合并到 html 里。
pytest --html=report.html --self-contained-html