当前位置:   article > 正文

python篇-pytest框架详解

pytest
Pytest框架
1.简介

pytest是纯python编写的自动化测试框架,可以支持python语法编写测试用例,是一个非常成熟的全功能的Python测试框架。

主要有以下几个特点:

  • 简单灵活,容易上手;
  • 支持参数化;
  • 能够支持简单的单元测试和复杂的功能测试,还可以结合selenium、requests做自动化测试;
  • pytest具有很多第三方插件,并且可以自定义扩展。

安装:pip install pytest

官方文档:https://docs.pytest.org

2.创建第一个pytest用例
  1. def test_01():
  2. assert 1 == 1
3.pytest命名规范
  • 测试模块:以 test_ 开头命名,如:test_login.py,或以 _test 结尾;

  • 测试类:必须以Test开头命名,且测试类中不能有 __init__ 方法;

  • 测试方法/测试函数:必须以test开头。

4.运行参数

无参数:读取路径下符合条件的所有类、函数、方法全部执行;
-v:打印详细运行日志;
-s:打印print输出;
-k: ​跳过运行某个或某些用例
pytest -k ‘类名’
pytest -k ‘方法名’
pytest -k ‘类名 and not 方法名’ # 运行类里所有方法,不包含某个方法
-x:运行用例失败立即停止运行
–maxfail
用例失败数达到某个设定的值停止运行
pytest --maxfail=[num]
-m 运行所有@pytest.mark.[标记名] 标记的用例

5.pytest实现数据驱动 pytest.mark.parametrize()

Pytest 测试框架的数据驱动是由 pytest 自带的pytest.mark.parametrize()来实现的。

@pytest.mark.parametrize() 装饰器接收两个参数:
第一个参数以字符串的形式存在,它代表能被测试函数所能接受的参数,如果被测试函数有多个参数,则以逗号分隔;
第二个参数用于保存测试数据。如果只有一组数据,以列表的形式存在,如果有多组数据,以列表嵌套元组的形式存在(例如: [1,1]或者[(1,1), (2,2)])。

实例

  1. class Test01:
  2. @pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
  3. def test_001(self,a,b,expect):
  4. print('测试a+b的结果')
  5. assert a+b==expect
  6. @pytest.mark.parametrize('c,d,expect', [(2, 4, 2), (9, 10, 1)])
  7. def test_002(self,c,d,expect):
  8. assert d-c==expect
  9. if __name__ == '__main__':
  10. pytest.main([__file__, '-k','test_001'])
6.pytest fixtures

6.1 fixture用途

  • fixture主要用来做初始化环境以及测试结束后的数据清除。
  • pytest fixture与setup,teardown功能一样,但比之更加灵活,完全可以代替setup,teardown。

 6.2 fixture参数详解

@pytest.fixture(scope='function',params=None,autouse=False,ids=None,name=None)
yield

fixture装饰器,相当于setup,测试用例的前置
* scope: 有四个级别参数'function(默认)'、'class'、'module'、'session'。
* params:一个可选的参数列表,列表中每个数据都可以作为用例的输入。也就说有多少数据,就会形成多少用例。可以通过request.param来获取该次调用的参数。
* autouse:如果True,自动调用fixture功能。如果为False则需要调用fixture。
* ids:每个字符串id的列表,每个字符串对应于params这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成。
* name:fixture的名称。这默认为装饰函数的名称。如果fixture在定义它的统一模块。
yield:这个关键字之后的代码相当于teardown,测试用例的后置。

6.3 fixture的作用范围

fixture里面有个scope参数可以控制fixture的作用范围:session>module>class>function
-function:每一个函数或方法都会调用
-class:每一个类调用一次,一个类中可以有多个方法
-module:每一个.py文件调用一次,该文件内又有多个function和class
-session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module

6.4 调用fixture的三种方法 

方式1:函数或类里直接传fixture的函数名称 

  1. @pytest.fixture()
  2. def test_fixture(self):
  3. print('\n用例开始执行fix1\n')
  4. yield
  5. print('\n用例执行结束fix1\n')
  6. def test_a(self, test_fixture):
  7. print('runing')
  8. assert 1 == 1

执行结果:

 

方式2: 使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例(可以叠加使用多个装饰器)

  1. @pytest.fixture()
  2. def test_fixture(self):
  3. print('\n用例开始执行fix1\n')
  4. yield
  5. print('\n用例执行结束fix1\n')
  6. @pytest.fixture()
  7. def test_fixture2(self):
  8. print('\n用例开始执行fix2\n')
  9. yield
  10. print('\n用例执行结束fix2\n')
  11. @pytest.mark.usefixtures('test_fixture')
  12. @pytest.mark.usefixtures('test_fixture2')
  13. def test_b(self):
  14. assert 1==1

执行结果

7.skip – 跳过测试 

7.1 pytest.skip() 用于函数内,跳过测试用例

  1. @pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
  2. def test_001(self,test1,a,b,expect):
  3. pytest.skip('跳过此测试用例')
  4. assert a+b==expect

用于函数外,跳过测试用例

  1. @pytest.mark.skip(reason="功能未实现")
  2. @pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
  3. def test_001(self,test1,a,b,expect):
  4. assert a+b==expect

 用在函数外,条件condition为True时,跳过用例

  1. @pytest.mark.skipif(condition=True,reason="功能未实现")
  2. @pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
  3. def test_001(self,test1,a,b,expect):
  4. assert a+b==expect

8.rerunfailure–失败重跑,插件pytest-rerunfailures

安装

  • 前提条件: pytest (>=5.3) 和python >=3.6
  • 安装:pip install pytest-rerunfailures
  • 查看安装版本:pip show pytest-rerunfailures

pytest-rerunfailures 使用

  • 命令行参数: --reruns n(重新运行次数)–reruns-delay m(等待运行秒数)
  • 使用装饰器: @pytest.mark.flaky(reruns=5, reruns_delay=2)

命令行实例

  1. #!/usr/bin/env python3
  2. # !coding:utf-8
  3. import pytest
  4. import random
  5. def test_simple_assume():
  6. # 每次case运行的值为1或者2,具有随机性
  7. r = random.randint(1, 3)
  8. assert r == 1
  9. if __name__ == '__main__':
  10. pytest.main(['Test_demo01.py', '-v', '--reruns=2', '--reruns-delay 2'])

配置执行次数越多(如--reruns=2),执行的成功率越高。

  • 命令行参数:

--reruns n(重新运行次数),--reruns-delay m(等待运行秒数)

例如

pytest pytest-demo.py --reruns 3 --reruns-delay 2

装饰器实例

  1. @pytest.mark.flaky(reruns=5, reruns_delay=2)
  2. def test_01(self):
  3. print('---用例01---')
  4. assert 1 == 2

 执行结果

9.Mark装饰器之order–执行顺序

需要先安装插件

cmd命令窗口:pip install pytest-ordering
在pycharm中File-->settings-->Project-->Python Interpreter-->点击+号-->搜索pytest-ordering安装。

查看安装版本:pip show pytest-ordering

使用方法:

  • 控制用例执行顺序的方法;
  • 在需要调整用例执行顺序的函数(或方法)前增加,如@pytest.mark.run(order=x),x表示数字;
  • 执行顺序,由小到大、由正到负、未标记的在正数后、负数前执行,顺序为:1,2,3,无标记,-3,-2,-1;

实例

  1. import pytest
  2. class Test_Class3():
  3. @pytest.mark.run(order=2)
  4. def test_case1(self):
  5. print("测试方法1")
  6. @pytest.mark.run(order=1)
  7. def test_case2(self):
  8. print("测试方法2")
  9. @pytest.mark.run(order=3)
  10. def test_case3(self):
  11. print("测试方法3")
  12. if __name__ == '__main__':
  13. pytest.main(['Test_demo02.py' '-s'])

执行结果

  1. ============================= test session starts =============================
  2. collecting ... collected 3 items
  3. Test_demo02.py::Test_Class3::test_case2 PASSED [ 33%]测试方法2
  4. Test_demo02.py::Test_Class3::test_case1 PASSED [ 66%]测试方法1
  5. Test_demo02.py::Test_Class3::test_case3 PASSED [100%]测试方法3
  6. ============================== 3 passed in 0.02s ==============================
10、setup、teardown,pytest方法名
setup_class()和 teardown_class()函数
需要定义在测试类中,定义在类外不起作用。
setup_class()定义场景,比如:创建日志对象,创建数据库的连接,创建接口的请求对象等。
teardown_class()定义场景,比如:销毁日志对象,销毁数据库的连接,销毁接口的请求对象。
  1. """
  2. 函数需要定义在测试类中,定义在类外不起作用。
  3. setup_method()和 teardown_method(),在每个测试方法之前/之后执行。定义场景,比如:打开浏览器/关闭浏览器。
  4. setup_class()定义场景,比如:创建日志对象,创建数据库的连接,创建接口的请求对象等。
  5. teardown_class()定义场景,比如:销毁日志对象,销毁数据库的连接,销毁接口的请求对象。
  6. """
  7. import pytest
  8. class Test_setUp_tearDown:
  9. # 方法级,前置函数
  10. def setup_method(self):
  11. # print("setup_method(self):在每个测试方法之前执行")
  12. print("在每个测试方法之前执行")
  13. # 方法级,后置函数
  14. def teardown_method(self):
  15. # print("teardown_method(self):在每个测试方法之后执行\n")
  16. print("在每个测试方法之后执行")
  17. # 类级,前置函数
  18. def setup_class(self):
  19. # print("setup_class(self):每个测试类之前执行一次\n")
  20. print("每个测试类之前执行一次")
  21. # 类级,后置函数
  22. def teardown_class(self):
  23. # print("teardown_class(self):每个测试类之后执行一次")
  24. print("每个测试类之后执行一次")
  25. # 测试用例a
  26. def test_a(self):
  27. print("test_a方法")
  28. assert True
  29. # 测试用例b
  30. def test_b(self):
  31. print("test_b方法")
  32. assert True
  33. if __name__ == '__main__':
  34. pytest.main()

11、问题:pytest执行的case,如果返回结果有中文,获取数据显示unicode编码格式

原因:是pytest默认将输出报告 视为ASCII字符串,并在测试报告中按原样显示。由于中文字符不属于ASCII字符范围,因此pytest会将其转换为Unicode编码表示。

解码后,pytest的执行报告才能正常显示中文。

使用语句:result = response.content.decode("unicode-escape")

参考文档:pytest框架详解_pytest框架 cllections.abc-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/733061
推荐阅读
相关标签
  

闽ICP备14008679号