Pytest+Allure

概述
pytest是一个非常成熟的全功能的Python测试框架,主要特点有以下几点:

1、简单灵活,容易上手,文档丰富;
2、支持参数化,可以细粒度地控制要测试的测试用例;
3、能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests);
4、pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等;
5、测试用例的skip和xfail处理;
6、可以很好的和CI工具结合,例如jenkins
环境配置
安装Python依赖库:
pip3 install pytest
pip3 install pytest-allure-adaptor

安装 Command Tool:
brew tap qatools/formulas
brew install allure-commandline

如何获取帮助信息
查看 pytest 版本

pytest --version
显示可用的内置函数参数

pytest --fixtures
通过命令行查看帮助信息及配置文件选项

pytest --help
编写规则
编写pytest测试样例非常简单,只需要按照下面的规则:

测试文件以test_开头(以_test结尾也可以)
测试类以Test开头,并且不能带有 init 方法
测试函数以test_开头
断言使用基本的assert即可

fixture的scope参数
scope参数有四种,分别是'function','module','class','session',默认为function。

function:每个test都运行,默认是function的scope
class:每个class的所有test只运行一次
module:每个module的所有test只运行一次
session:每个session只运行一次
setup和teardown操作
setup,在测试函数或类之前执行,完成准备工作,例如数据库链接、测试数据、打开文件等
teardown,在测试函数或类之后执行,完成收尾工作,例如断开数据库链接、回收内存资源等
备注:也可以通过在fixture函数中通过yield实现setup和teardown功能

如何执行
pytest # run all tests below current dir
pytest test_mod.py # run tests in module file test_mod.py
pytest somepath # run all tests below somepath like ./tests/
pytest -k stringexpr # only run tests with names that match the

the "string expression", e.g. "MyClass and not method"

will select TestMyClass.test_something

but not TestMyClass.test_method_simple

pytest test_mod.py::test_func # only run tests that match the "node ID",

e.g "test_mod.py::test_func" will be selected

only run test_func in test_mod.py

Console参数介绍
-v 用于显示每个测试函数的执行结果
-q 只显示整体测试结果
-s 用于显示测试函数中print()函数输出
-x, --exitfirst, exit instantly on first error or failed test
-h 帮助

在第N个用例失败后,结束测试执行
pytest -x # 第01次失败,就停止测试
pytest --maxfail=2 # 出现2个失败就终止测试
执行特定用例
指定测试模块
pytest test_mod.py
指定测试目录
pytest testing/
通过关键字表达式过滤执行
pytest -k "MyClass and not method"
这条命令会匹配文件名、类名、方法名匹配表达式的用例,这里这条命令会运行 TestMyClass.test_something, 不会执行 TestMyClass.test_method_simple

通过 node id 指定测试用例
nodeid由模块文件名、分隔符、类名、方法名、参数构成,举例如下:
运行模块中的指定用例

pytest test_mod.py::test_func
运行模块中的指定方法

ytest test_mod.py::TestClass::test_method
通过标记表达式执行
pytest -m slow
这条命令会执行被装饰器 @pytest.mark.slow 装饰的所有测试用例

通过包执行测试
pytest --pyargs pkg.testing
这条命令会自动导入包 pkg.testing,并使用该包所在的目录,执行下面的用例

获取用例执行性能数据
获取最慢的10个用例的执行耗时

pytest --durations=10
生成 JUnitXML 格式的结果文件
这种格式的结果文件可以被Jenkins或其他CI工具解析

pytest --junitxml=path
禁用插件
例如,关闭 doctest 插件

pytest -p no:doctest

Pytest 的 Exit Code 含义清单
Exit code 0 所有用例执行完毕,全部通过
Exit code 1 所有用例执行完毕,存在Failed的测试用例
Exit code 2 用户中断了测试的执行
Exit code 3 测试执行过程发生了内部错误
Exit code 4 pytest 命令行使用错误
Exit code 5 未采集到可用测试用例文件

  1. 扩展插件
    3.1. 测试报告

安装与样例
pip install pytest-cov # 计算pytest覆盖率,支持输出多种格式的测试报告
pytest --cov-report=html --cov=./ test_code_target_dir

Console参数介绍
--cov=[path], measure coverage for filesystem path (multi-allowed), 指定被测试对象,用于计算测试覆盖率
--cov-report=type, type of report to generate: term, term-missing, annotate, html, xml (multi-allowed), 测试报告的类型
--cov-config=path, config file for coverage, default: .coveragerc, coverage配置文件
--no-cov-on-fail, do not report coverage if test run fails, default: False,如果测试失败,不生成测试报告
--cov-fail-under=MIN, Fail if the total coverage is less than MIN. 如果测试覆盖率低于MIN,则认为失败
Console Result
---------------------------------------------------------------- coverage: platform linux2, python 2.7.14-final-0 ----------------------------------------------------------------

Name Stmts Miss Cover

pytest1.py 18 0 100%
Html Result

image.png
3.2. 测试顺序随机
pip install pytest-randomly

3.3. 分布式测试
pip install pytest-xdist

3.4. 出错立即返回
pip install pytest-instafail

安装Allure Pytest Adaptor
Allure Pytest Adaptor是Pytest的一个插件,通过它我们可以生成Allure所需要的用于生成测试报告的数据。安装pytest-allure-adaptor插件方法:

example:
com.atlassian.confluence.content.render.xhtml.XhtmlException: Missing required attribute: {http://atlassian.com/resource/identifier}value
@allure.severity("critical") # 优先级,包含blocker, critical, normal, minor, trivial 几个不同的等级
@allure.feature("测试模块_demo1") # 功能块,feature功能分块时比story大,即同时存在feature和story时,feature为父节点
@allure.story("测试模块_demo2") # 功能块,具有相同feature或story的用例将规整到相同模块下,执行时可用于筛选
@allure.issue("BUG号:123") # 问题表识,关联标识已有的问题,可为一个url链接地址
@allure.testcase("用例名:测试字符串相等") # 用例标识,关联标识用例,可为一个url链接地址

Allure中对严重级别的定义:

  1. Blocker级别——中断缺陷
    客户端程序无响应,无法执行下一步操作。
  2. Critical级别――临界缺陷,包括:
    功能点缺失,客户端爆页。
  3. Major级别——较严重缺陷,包括:
    功能点没有满足需求。
  4. Normal级别――普通缺陷,包括:

    1. 数值计算错误
    2. JavaScript错误。
  5. Minor级别———次要缺陷,包括:

    1. 界面错误与UI需求不符。
    2. 打印内容、格式错误
    3. 程序不健壮,操作未给出明确提示。
  6. Trivial级别——轻微缺陷,包括:

    1. 辅助说明描述不清楚
    2. 显示格式不规范,数字,日期等格式。
    3. 长时间操作未给用户进度提示
    4. 提示窗口文字未采用行业术语
    5. 可输入区域和只读区域没有明显的区分标志
    6. 必输项无提示,或者提示不规范。
  7. Enhancement级别——测试建议、其他(非缺陷)

    1. 以客户角度的易用性测试建议。
    2. 通过测试挖掘出来的潜在需求。

生成html报告命令
1、pytest命令基础上加--alluredir,生成xml报告。

pytest -s -q --alluredir [xml_report_path]
//[xml_report_path]根据自己需要定义文件夹,作者定义为:/report/xml

用例执行完成之后会在[xml_report_path]目录下生成了一堆xml的report文件,当然这不是我们最终想要的美观报告。

2、需要使用 Command Tool 来生成我们需要的美观报告。

allure generate [xml_report_path] -o [html_report_path]
//[html_report_path]根据自己需要定义文件夹,作者定义为:/report/html

打开 index.html,之前写的 case 报告就会呈现在你面前

注️:直接用chrome浏览器打开报告,报告可能会是空白页面。
解决办法:
1、在pycharm中右击index.html选择打开方式Open in Browser就可以了。
2、使用Firefox直接打开index.html。

三、定制报告
Feature: 标注主要功能模块
Story: 标注Features功能模块下的分支功能
Severity: 标注测试用例的重要级别
Step: 标注测试用例的重要步骤
Issue和TestCase: 标注Issue、Case,可加入URL
attach: 标注增加附件
Environment: 标注环境Environment字段

1、Features定制详解

-- coding: utf-8 --

@Time : 2018/8/17 上午10:10

@Author : WangJuan

@File : test_case.py

import allure
import pytest

@allure.feature('test_module_01')
def test_case_01():

""" 用例描述:Test case 01 """
assert 0

@allure.feature('test_module_02')
def test_case_02():

""" 用例描述:Test case 02 """
assert 0 == 0

if name == '__main__':

pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加feature,Report展示见下图。

2、Story定制详解

-- coding: utf-8 --

@Time : 2018/8/17 上午10:10

@Author : WangJuan

@File : test_case.py

import allure
import pytest

@allure.feature('test_module_01')
@allure.story('test_story_01')
def test_case_01():

""" 用例描述:Test case 01 """
assert 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
def test_case_02():

""" 用例描述:Test case 02 """
assert 0 == 0

if name == '__main__':

pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加story,Report展示见下图。

3、用例标题和用例描述定制详解

-- coding: utf-8 --

@Time : 2018/8/17 上午10:10

@Author : WangJuan

@File : test_case.py

import allure
import pytest

@allure.feature('test_module_01')
@allure.story('test_story_01')

test_case_01为用例title

def test_case_01():

""" 用例描述:这是用例描述,Test case 01,描述本人 """
#注释为用例描述
assert 0

if name == '__main__':

pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加用例标题和用例描述,Report展示见下图。

4 、Severity定制详解
Allure中对严重级别的定义:
1、 Blocker级别:中断缺陷(客户端程序无响应,无法执行下一步操作)
2、 Critical级别:临界缺陷( 功能点缺失)
3、 Normal级别:普通缺陷(数值计算错误)
4、 Minor级别:次要缺陷(界面错误与UI需求不符)
5、 Trivial级别:轻微缺陷(必输项无提示,或者提示不规范)

-- coding: utf-8 --

@Time : 2018/8/17 上午10:10

@Author : WangJuan

@File : test_case.py

import allure
import pytest

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
def test_case_01():

""" 用例描述:Test case 01 """
assert 0

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('critical')
def test_case_02():

""" 用例描述:Test case 02 """
assert 0 == 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
@allure.severity('normal')
def test_case_03():

""" 用例描述:Test case 03 """
assert 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
@allure.severity('minor')
def test_case_04():

""" 用例描述:Test case 04 """
assert 0 == 0

if name == '__main__':

pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加Severity,Report展示见下图。

5、Step定制详解

-- coding: utf-8 --

@Time : 2018/8/17 上午10:10

@Author : WangJuan

@File : test_case.py

import allure
import pytest

@allure.step("字符串相加:{0},{1}")

测试步骤,可通过format机制自动获取函数参数

def str_add(str1, str2):

if not isinstance(str1, str):
    return "%s is not a string" % str1
if not isinstance(str2, str):
    return "%s is not a string" % str2
return str1 + str2

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
def test_case():

str1 = 'hello'
str2 = 'world'
assert str_add(str1, str2) == 'helloworld'

if name == '__main__':

pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加Step,Report展示见下图。

6、Issue和TestCase定制详解

-- coding: utf-8 --

@Time : 2018/8/17 上午10:10

@Author : WangJuan

@File : test_case.py

import allure
import pytest

@allure.step("字符串相加:{0},{1}") # 测试步骤,可通过format机制自动获取函数参数
def str_add(str1, str2):

print('hello')
if not isinstance(str1, str):
    return "%s is not a string" % str1
if not isinstance(str2, str):
    return "%s is not a string" % str2
return str1 + str2

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
@allure.issue("http://www.baidu.com")
@allure.testcase("http://www.testlink.com")
def test_case():

str1 = 'hello'
str2 = 'world'
assert str_add(str1, str2) == 'helloworld'

if name == '__main__':

pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加Issue和TestCase,Report展示见下图。

7、Environment定制详解

具体Environment参数可自行设置

allure.environment(app_package='com.mobile.fm')
allure.environment(app_activity='com.mobile.fm.activity')
allure.environment(device_name='aad464')
allure.environment(platform_name='Android')

添加Environment参数,Report展示见下图。

8、attach定制详解
file = open('../test.png', 'rb').read()
allure.attach('test_img', file, allure.attach_type.PNG)
在报告中增加附件:allure.attach(’arg1’,’arg2’,’arg3’):
arg1:是在报告中显示的附件名称
arg2:表示添加附件的内容
arg3:表示添加的类型(支持:HTML,JPG,PNG,JSON,OTHER,TEXTXML)

添加attach参数,Report展示见下图。

此外,Allure还支持Jenkins Plugin~

上一篇:第一篇:SpringCloud 构建微服务系统之服务注册和发现(consul)


下一篇:《数据库技术原理与应用教程》一3.6.2磁盘存储器及其操作