pytest入门基础

参考学习官网文档:https://docs.pytest.org/en/latest/getting-started.html

一、pytest简介

1. 前言:测试框架与测试工具

  • 测试框架、测试工具这两个概念经常容易搞混了,测试框架是诸如 Unittest、Pytest、TestNG 这类,而测试工具指的则是 Selenium、Appium、Jmeter 这类。
  • 测试框架的作用是,帮助管理测试用例、执行测试用例、参数化、断言、生成测试报告等基础性工作,让我们将精力用在测试用例的编写上。好的测试框架应该具有很高的扩展性,支持二次开发,并能够支持多种类型的自动化测试。
  • 测试工具的作用是为了完成某一类型的测试,比如 Selenium 用于对 WEB UI 进行自动化测试,Appium 用来对 APP 进行自动化测试,Jmeter 可以用来进行 API 自动化测试和性能测试。另外,Java 语言中 OkHttp 库,Python 语言中的 requests 库,这些 HTTP 的 client 也可以看做是一种 API 测试工具。

2. 单元测试框架

  • 1)什么是单元测试框架?
    单元测试是指软件开发中,针对软件的最小单位(函数、方法)进行正确性的检查测试,Java:junit、testing
    Python:unittest、pytest
  • 2)单元测试框架主要做什么?
    ① 测试发现:从多个文件里面去找我们得测试用例
    ② 测试执行:按照一定的顺序和规则去执行,并生成结果
    ③ 测试判断:通过断言判断预期结果和实际结果的差异
    ④ 测试报告:统计测试进度、耗时、通过率、生成测试报告

3. pytest简介

  • Pytest 是 Python 的一种易用、高效和灵活的单元测试框架,可以支持单元测试和功能测试
  • pytest可以和selenium,requests,appium结合实现web自动化、接口自动化、app自动化
  • pytest可以实现测试用例的跳过以及reruns(失败用例重试)
  • pytest可以和allure生成非常美观的测试报告
  • pytest可以和jenkins持续集成
  • pytest有很多非常强大的插件,并且这些插件能够实现很多实用的操作
    ① pytest-xdist:测试用例分布式执行,多cpu分发
    ② pytest-ordering:用于改变测试用例的执行顺序
    ③ pytest-rerunfailures:用例失败后重跑
    ④ pytest-html:生成html格式的自动化测试报告
    ⑤ allure-pytest:用于生成美观测试报告


二、安装pytest

pytest需要:Python 3.7+ 或 PyPy3

  1. 在命令行中运行以下命令
pip install -U pytest

其他插件安装方法也是一样pip安装

  1. 检查是否安装成功
    pytest


三、pytest使用规则

  1. 模块名必须以test_开头或test_结尾
  2. 测试类必须以Test开头,且不能有init方法
  3. 测试方法必须以test开头
    使用规则


四、测试用例执行

pytest 用例的执行主要有以下三种方式:

  • 通过命令模式执行
  • 通过主函数执行
  • 通过读取 pytest.ini 配置文件执行

4.1 通过命令模式执行

测试文件test_demo.py:Pytest 使用 Python 的 assert 进行条件判断,简单的测试函数如:

def test_product_case001():
    print("模拟测试模块1的功能")
    assert 1 + 1 == 3


def test_product_case002():
    print("模拟测试模块2的功能")
    assert 1 == 1
1)执行所有用例

pytest 命令执行当前目录下所有的测试用例,所以要想执行项目中所有的用例,只需要将执行目录切换到根目录即可:

image.png

可以加上-v参数查看详情pytest -v

image.png

2)指定执行

执行指定目录:
执行指定目录

执行指定文件:
执行指定文件

执行指定用例:
执行指定用例


4.2 通过主函数执行

1)主函数运行

test_demo.py添加主函数:

import pytest

class Testdemo:
    def test_case_passed(self):
        print("模拟执行成功场景的case")
        assert (1, 2, 3) == (1, 2, 3)

def test_case_failed():
    print("模拟执行失败场景的case")
    assert 3 == 1 + 1

if __name__ == '__main__':
    pytest.main(["-v"])    # 执行测试用例,-v参数打印详细信息

然后直接运行:
执行结果

从终端的打印可以看到,用例文件中的用例方法 test_case_failed 以及测试类中的测试方法 test_case_passed 都被执行了。

2)批量执行

只需要在对应的用例文件中调用主函数,就可以自动执行文件中的所有用例。
但是在实际的使用中,一般会将用例分类写在不同目录下的不同用例文件里,且执行时要批量去执行所有的用例,所以往往会将主函数写在一个与用例文件夹平级的 py 文件中,pytest 内部设有对应的机制,会自动扫描全局,执行所有的用例文件。

主函数文件所在目录:
主函数文件

运行主函数文件main.py,输出结果可以看到所有用例均被执行了:

批量执行

3)指定执行

pytest.main()可以加上命令参数运行,如下

指定目录
指定目录

指定文件
指定文件

指定用例
指定用例


4.3 通过 pytest.ini 配置文件执行

在项目中,通常通过配置全局的配置文件来执行测试用例的。其余两种执行方式在编写和调试用例时比较方便。对于配置文件,有以下几点要求:

  • 配置文件的名字必须为 pytest.ini
  • 配置文件一般放置在项目的根目录
  • 配置文件必须时 ANSI 编码
  • 配置了pytest.ini文件后,不管是主函数模式运行用例,还是命令行模式运行用例,都会去读取pytest.ini配置文件中的内容。
  • CMD命令行中执行pytest -h命令,可以查看pytest.ini的设置选项。

pytest.ini 是 pytest 框架的核心配置文件,它可以改变 pytest 的默认行为,不管是通过主函数还是命令模式去执行用例,都会先去读取配置文件。

修改完配置文件,再去执行用例时就会按照配置文件的要求去执行:
配置文件


五、执行参数

我们在执行用例时,可以通过添加相关的参数实现不同的执行效果,提升测试效率。

1)-s:用于输出调试信息,包括打印输出的信息

# 通过main函数执行
pytest.main(["-s", "./product_cases/test_product.py"])
# 通过命令模式执行
pytest -s ./product_cases/test_product.py
-s

2)-v:显示更详细的信息

# 通过main函数执行
pytest.main(["-v", "./product_cases/test_product.py"])
# 通过命令模式执行
pytest -v ./product_cases/test_product.py
-v

3)-vs:将 -v 和 -s 参数效果结合,推荐使用
-vs

4)-n:支持多线程或者分布式运行测试用例

n是进程数,也就是cpu个数,最大值为当前机器cpu个数,也可以设置为auto,自动识别cpu个数。

# 通过main函数执行
# 开两个线程去执行用户操作目录下所有的用例
pytest.main(["-vs", "./product_cases", "-n=2"])

# 通过命令模式执行
pytest -vs ./product_cases -n 2

为了方便看出测试效果,给test_product.py文件中的每个测试用例都增加sleep(2)

import pytest,time


def test_product_case001():
    time.sleep(2)
    print("模拟测试模块1的功能")
    assert 1 + 1 == 2


def test_product_case002():
    time.sleep(2)
    print("模拟测试模块2的功能")
    assert 1 == 1

正常执行结果:用时4.05s
单线程执行

开启2个线程执行结果:用时2.60s
多线程执行

5)--reruns:失败用例重跑

# 通过main函数执行
# 如果用例执行失败,该用例再执行2次
pytest.main(["-vs", "./product_cases", "--reruns=2"])

# 通过命令模式执行
pytest -vs ./product_cases --reruns 2

修改test_product.py文件

def test_product_case001():
    print("模拟测试模块1的功能")
    assert 1 + 1 == 3


def test_product_case002():
    print("模拟测试模块2的功能")
    assert 1 == 1
失败重跑

6)-x:只要有一个用例失败,就停止执行

# 通过main函数执行
pytest.main(["-vs", "./product_cases", "-x"])

# 通过命令模式执行
pytest -vs ./product_cases -x

test_product_case001失败,停止执行,test_product_case002未执行

失败停止执行g

7)--maxfail:失败的用例数达到规定值时停止测试

# 失败的用例数达到2个时停止测试
# 通过main函数执行
pytest.main(["-vs", "./product_cases", "--maxfail=2"])

# 通过命令模式执行
pytest -vs ./product_cases --maxfail 2
失败停止测试

8)-k:关键字过滤执行

-k会匹配文件名、类名、方法名匹配表达式的用例,如果指定的表达式是被文件名/测试类名包含的,那么文件/测试类中所有的测试方法都会被执行。

# 执行文件名/类名/方法名中包含01的用例
# 通过main函数执行
pytest.main(["-vs", "./product_cases", "-k=01"])

# 通过命令模式执行
pytest -vs ./product_cases -k="01"

指定执行测试用例名称包含01

过滤执行

指定执行测试用例名称包含login

过滤执行

9)--html:用例执行完成后生成 html 格式的测试报告

pytest -vs --html ./report/result.html --html+报告存放路径参数

生成html报告

result.html


六、用例执行顺序

修改 test_product.py 中测试方法:

def test_product_case():
    print("模拟测试产品相关的操作")

def test_case_001():
    print("测试方法_001")

def test_case_002():
    print("测试方法_002")

def test_case_003():
    print("测试方法_003")

def test_case_004():
    print("测试方法_004")

def test_case_005():
    print("测试方法_005")

1)默认执行顺序

pytest 对于用例的执行顺序是按照从上到下执行的

从上往下执行

2) 改变用例的执行顺序

通过装饰器方法@pytest.mark.run()可以改变用例的执行顺序,参数order=n指定排在第n个执行

# product_cases/test_product.py
import pytest

def test_product_case():
    print("模拟测试产品相关的操作")

# 通过装饰器方法 @pytest.mark.run() 可以改变用例的执行顺序
# order参数表示该用例要排在第几个执行
@pytest.mark.run(order=1)
def test_case_002():
    print("测试方法_002")

@pytest.mark.run(order=2)
def test_case_003():
    print("测试方法_003")

def test_case_004():
    print("测试方法_004")

def test_case_005():
    print("测试方法_005")
指定执行顺序

从终端输出的结果可以看到,被装饰器装饰的测试用例都按照了指定的顺序执行,没有被装饰到的用例还是按照从上到下的顺序执行


七、标记函数,分组执行用例

1)装饰器@pytest.mark.name装饰用例

第一步,使用装饰器@pytest.mark.name去装饰要执行的用例,其中 name 为自定义的名称

# product_cases/test_product.py
import pytest

# 通过装饰器方法 @pytest.mark.finished标记已完成的用例
@pytest.mark.finished
def test_product_case():
    print("模拟测试产品相关的操作")

# 通过装饰器方法 @pytest.mark.unfinished标记未完成功能的用例
@pytest.mark.unfinished
def test_case_002():
    print("测试方法_002")

@pytest.mark.unfinished
def test_case_003():
    print("测试方法_003")

def test_case_004():
    print("测试方法_004")

def test_case_005():
    print("测试方法_005")

2)pytest.ini 添加分组配置

第二步,去 pytest.ini 中添加分组配置,配置名必须和装饰器中的 name 值一致
配置文件pytest.ini

3)参数 -m 指定执行用例

第三步,执行时通过参数 -m 指定要执行的用例
执行标记用例


八、跳过用例

对于某些不想执行的用例,可以使用 pytest 提供的装饰器方法@pytest.mark.skip()跳过该用例不去执行

1)直接跳过

装饰器语法:@pytest.mark.skip(reason="") ,reason 参数可选,表示跳过该测试方法的原因

@pytest.mark.skip

2)条件跳过

装饰器语法:@pytest.mark.skipif(判断条件, reason="") ,为测试函数指定被忽略的条件,reason 参数可选

# product_cases/test_product.py
import pytest

version = 1

# V2版本才支持,版本小于V2则跳过不执行
@pytest.mark.skipif(version < 2, reason='not supported until v2')
def test_product_case():
    print("模拟测试产品相关的操作")

def test_case_001():
    print("测试方法_001")

def test_case_002():
    print("测试方法_002")
  • version=1满足条件,跳过不执行
    满足条件跳过
  • version=2不满足条件,不跳过执行
    不满足条件不跳过

文章转载参考:http://www.chendacheng.com/content/?category=Pytest%E4%B8%93%E9%A2%98&article=Pytest_01.html

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容