pytest进阶
使用 pytest
pytest 这个 库是一个第三方库,严格来说,它的设计思路不属于 xUnit 系列。但它使用起来比较方便,同时他又兼容 unittest 的用例:用 unittest 写的测试脚本可以用 pytest 来执行。
这种兼容性的设计,在测试执行器的设计思路层面上很普遍。举个例子,几乎所有测试执行器,都兼容 junit 的测试报告,他们都可以输出一种 最初由 junit 提供的 xml 测试报告(有些测试执行器是原生自带这个功能,有些是用插件实现这个功能)。兼容现有工具,有利于新工具的推广,因此各种比较知名的测试执行器都会从设计上就考虑兼容性。
言归正传,接下来介绍 测试执行器的几个重点功能,以及我们怎样用 pytest 里的这些功能。
任务1.安装 pytest
和其他python 库一样我们使用 pip install pytest 来安装pytest
任务2.打开官方文档
测试命名规范
pytest 里,测试用例的定义较 unittest 做了简化。
1.类名规范取消,不用继承任何类
上一节的例子中,
我们使用unittest时,需要把测试写在类里,这个类还必须继承 unittest.TestCase 像这样:
class TestStringMethods(unittest.TestCase):
只有继承了 unittest.TestCase 这个类,unittest 才能找到这个类里我们写的测试方法。
而pytest 里,不再强制要求把测试写在类里,也不需要继承任何类。
取而代之的,是使用文件名规范来让pytest 找到我们写的测试方法的文件。
2.文件名以 test_ 开头,注意带下划线
例1.test_1540.py,一个pytest的例子。注意文件名。
import pytestdef inc(x):
return x + 1def test_answer():
assert inc(3) == 5if __name__ == '__main__':
pytest.main()
我们一起来看一下这个例子:
首先第一行,导入 pytest 库
第2-3 行,定义了一个 inc 方法,这个方法会把传入参数加1,再返回。
第4-5 行,定义了一个 test 方法,这一点和unittest 一样,测试方法名要以 test 开头
第6-7行, 定义了程序的入口,这两行可以省略
断言
官方文档中告诉我们,pytest的断言里只要用assert 就行了,不需要 self.assertXXXX。
pytest 会显示这样 的错误信息给我们,以下为例1的运行结果:
============================FAILURES===============
_______________________________ test_answer ________________________________
def test_answer():
> assert inc(3) == 5
E assert 4 == 5
E + where 4 = inc(3)
test_1540.py:7: AssertionError
=================== 1 failed in 0.07 seconds=================
并且上一节中我们用过的自定义更详细的错误信息的方法在这里仍然适用。
setup和teardown
所谓 setup 和 teardown,也是 xUnit 系列测试执行器中的概念。比如,假设我们有3个测试方法,都是操作在线购物网站的购物车的测试,他们有一个共同的前提条件,就是用户需要先登录。那么通常在 xUnit 系列的测试执行器中,测试脚本我们会这样写:

上图示意了一个带有 setup 和teardown 操作的测试套件(test suite)的内部逻辑,这里的 setup 和teardown 是对测试套件的,同样也可以定义对 Case 的和对测试方法的 setup 和teardown 。
当执行一个测试套件时,其顺序是:
套件的 steup====》
case1 的setup====》 case1 的测试方法====》 case1的teardown ====》
case2 的setup====》 case2 的测试方法====》 case2的teardown ====》
case3 的setup====》 case3 的测试方法====》 case3的teardown ====》
套件的 teardown
在pytest中,也支持上述的传统 setup 和 teardown,感兴趣的同学可以看官方文档:
https://docs.pytest.org/en/latest/xunit_setup.html#xunitsetup
本文中,将介绍 pytest 的fixture 以及用fixture实现的 setup和 teardown
Pytest的Fixture
fixture 是什么?
我们可以理解成 fixture 是提供给测试方法用的提前准备好的对象。
举个例子,我们做网页测试,需要先打开一个浏览器,后续所有操作都是在这个浏览器上做的。 fixture 能做的就是给我们的每个测试方法,都准备好一个浏览器对象。
同样,我们做一些测试时,需要先读取一个 excel表格,然后所有测试方法,都需要用这个表格里的某些数据,那么fixture能做的就是给每个测试方法,都准备好一个已经读取完毕的 excel 表格对象。
我们一起来看一个官网的例子:
例2.官网给的 fixture 例子
# content of conftest.py
import pytest import smtplib
@pytest.fixture(scope="module") def smtp_connection():
return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
# content of test_module.py
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
assert 0 # for demo purposes
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
assert 0 # for demo purposes
这个例子里涉及了 conftest.py 和 test_module.py 两个文件
在conftest.py 中,定义了一个 smtp_connection 方法,这个方法使用 smtplib 这个库去建立了一个 gmail 的链接,也就是这两行
def smtp_connection():
return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
而 @pytest.fixture(scope="module") 这一行表示后面紧跟的 smtp_connection 方法是一个fixutre,并且范围是整个module。 范围是 module,则表示这个fixture 在每个module 只会运行一次。在这里,module的 概念和测试套件差不多。本例中,整个 module 也就只有两个测试方法。 也就是说:
这个 smtp_connection 方法在这次整个测试中只会被执行一次。换句话说,它就相当于是 整个测试套件的 setup 方法了。
在 test_module.py 中,定义了两个测试方法,这两个测试方法的共同点是,传入参数里都有 smtp_connection。 没错,这里的smtp_connection就是 conftest中的 smtp_connection 的返回值。
虽然官网的例子我们无法运行,但是我们可以一起来回顾一下整个测试执行过程:
1.先找到所有 test_开头的文件,称为测试脚本文件
2.在测试脚本文件同一级目录下寻找conftest.py,称为测试配置文件
3.按随机顺序执行测试脚本文件中的测试方法
4.执行第一个测试方法,发现有一个传入参数 smtp_connection,在测试配置文件中寻找名为 smtp_connection 的fixture
5.执行测试配置文件中的 smtp_connection 方法,保存返回值
6.把上一步的返回值代入第4步的测试方法传入参数中,执行第一个测试方法
7.执行第二个测试方法,发现有一个传入参数 smtp_connection ,在测试配置文件中寻找名为 smtp_connection 的fixture
8.发现这个fixture的范围是module,无需重复执行,使用第5步的返回值继续执行第7步的第二个测试方法。
理解了上述流程,我们发现, fixture 其实就相当于是 setup方法,并且更灵活:
通过修改 fixture 的 scope (它的值可以是 module,class或fucntion)我们可以给每个方法、每个类定制不同的fixture。 同样,fixture其实也可以定义teardown方法。
例3.在官网例子上增加 teardown
@pytest.fixture(scope="module")
def smtp_connection():
yield smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
print("我就是 teardown,我在测试方法结束后运行")
这个例子中,第四行的 return 改成了 yield。而 第五行开始的内容就会在测试方法执行结束后运行了。相当于是实现了teardown。
下面一起看一个可以运行的例子:
例4.一个用fixture 实现测试方法级别的setup和teardown的例子:
#conftest.py的内容
import pytest
@pytest.fixture(scope="function",autouse=True)
def foo():
print(" function setup")
yield 100
print(" function teardown")
#test_1540.py的内容
import pytest
def inc(x):
return x + 1
def test_answer_1():
assert inc(3) == 5
def test_answer_2(foo):
print(foo)
assert inc(98) == foo
if __name__ == '__main__':
pytest.main()
一起来看一下这个例子,
在文件conftest.py里,
第2行,使用了装饰器 pytest.fixture,这个装饰器带的参数值表示这个fixture的生效范围是方法级(scope= “function”),也就是说每个方法之前之后都会运行它。并且会自动使用(autouse=True),这个自动使用为真时,我们在测试方法的传入参数表里可以省略这个 fixture的方法名。当然,如果在传入参数里省略了foo,那么就无法使用 foo的返回值。所以一般要自动使用的fixture都是没有返回值的。
第3-6行定义了这个fixture foo,并且返回值固定为100。 返回值 使用 yield 来返回,这样 yield 后的语句会在 测试方法执行后被执行。
运行这个例子的结果如下:
rootdir: C:\Users\colin.zt\Desktop\Homework_20180914\15.0, inifile:
collected 2 items
test_1540.py FF [100%]
================ FAILURES==========================
________________________________ test_answer_1 ________________________________
def test_answer_1():
> assert inc(3) == 5
E assert 4 == 5
E + where 4 = inc(3)
test_1540.py:9: AssertionError
---------------------------- Captured stdout setup ----------------------------
function setup
-------------------------- Captured stdout teardown ---------------------------
function teardown
________________________________ test_answer_2 ________________________________
foo = 100
def test_answer_2(foo):
print(foo)
> assert inc(98) == foo
E assert 99 == 100
E + where 99 = inc(98)
test_1540.py:14: AssertionError
---------------------------- Captured stdout setup ----------------------------
function setup
---------------------------- Captured stdout call -----------------------------
100
-------------------------- Captured stdout teardown ---------------------------
function teardown
========== 2 failed in 0.08 seconds ================
其中需要说明的部分是:Captured stdout setup 和 Captured stdout teardown 这两部分是 pytest 抓取的 setup 和teardown部分的日志,其内容是我们在 foo方法里输出的内容。可以看到上述结果中,共抓到了两次 setup和两次 teardown,这是因为我们的foo方法 范围是 function,而我们有两个测试方法。因此每个测试方法前后都会执行 foo方法的对应语句。
另外,def test_answer_1(): 这个方法里没有显式传入参数 foo,但因为 foo的autouse = True,所以test_answer_1方法执行前后也会执行 foo 方法。
而 def test_answer_2(foo):里显式传入了参数 foo,那么除了执行foo 方法以外,传输参数 foo 还会带有foo 方法的返回值,即 100。
pytest进阶的更多相关文章
- pytest进阶之配置文件
前言 pytest配置文件能够改变pytest框架代码的运行规则.比如修改pytest收集用例的规则,添加命令行参数等等!下面我们来一一讲解常用的一些配置项 Help 通过命令pytest --hel ...
- pytest进阶之html测试报告
前言 Pytest系列已经写了几篇文章了,也不知道对多少人有帮助,总之对于我自己来说该掌握的都已经掌握了,那么今天我们再来说说pytest如何生成一个完整的html测试报告,让你在吹牛逼的路上再多一份 ...
- pytest进阶之xunit fixture
前言 今天我们再说一下pytest框架和unittest框架相同的fixture的使用, 了解unittest的同学应该知道我们在初始化环境和销毁工作时,unittest使用的是setUp,tearD ...
- pytest进阶之conftest.py
前言 前面几篇随笔基本上已经了解了pytest 命令使用,收集用例,finxture使用及作用范围,今天简单介绍一下conftest.py文件的作用和实际项目中如是使用此文件! 实例场景 首先们思考这 ...
- pytest进阶之fixture
前言 学pytest就不得不说fixture,fixture是pytest的精髓所在,就像unittest中的setup和teardown一样,如果不学fixture那么使用pytest和使用unit ...
- Pytest - 进阶功能fixture
1. 概述 Pytest的fixture功能灵活好用,支持参数设置,便于进行多用例测试,简单便捷,颇有pythonic.如果要深入学习pytest,必学fixture. fixture函数的作用: 完 ...
- Pytest进阶之参数化
前言 unittest单元测试框架使用DDT进行数据驱动测试,那么身为功能更加强大且更加灵活的Pytest框架怎么可能没有数据驱动的概念呢?其实Pytest是使用@pytest.mark.parame ...
- pytest进阶之fixture函数
fixture函数存在意义 与python自带的unitest测试框架中的setup.teardown类似,pytest提供了fixture函数用以在测试执行前和执行后进行必要的准备和清理工作.但是相 ...
- pytest进阶使用【fixture(一)fixture与setup/teardown区别】
fixture翻译为装置. 我觉得名字是很贴合功能的,可以自由给函数装置上自己想要的功能. 当在说pytest比unitest灵活时,fixture肯定是其中的一个理由. 测试数据的准备和执行以后的数 ...
随机推荐
- java字节码文件
查看字节码文件: javap -verbose HellloWorld.class
- vuex详细介绍和使用方法
1.什么是vuex? 官方的解释: Vuex是一个专为Vue.js应用程序开发的状态管理模式 当项目比较庞大的时候,每个组件的状态比较多,为了方便管理,需要把组件中的状态抽取出来,放入Vuex中进行统 ...
- Solidity数组
一.固定长度的数组(Arrays) 1.固定长度类型数组的声明 pragma solidity ^0.4.4; contract C { // 数组的长度为5,数组里面的存储的值的类型为uint类型 ...
- KMP字符串匹配算法理解(转)
一.引言 主串(被扫描的串):S='s0s1...sn-1',i 为主串下标指针,指示每回合匹配过程中主串的当前被比较字符: 模式串(需要在主串中寻找的串):P='p0p1...pm-1',j 为模式 ...
- ArcGIS紧凑型切片读取与应用2-webgis动态加载紧凑型切片(附源码)
1.前言 上篇主要讲了一下紧凑型切片的的解析逻辑,这一篇主要讲一下使用openlayers动态加载紧凑型切片的web地图服务. 2.代码实现 上篇已经可以通过切片的x.y.z得对应的切片图片,现在使用 ...
- select函数用法详解
1. select函数 select的作用: 轮询的方式,从多个文件描述符中获取状态变化后的情况. 头文件 #include <sys/time.h> //for struct timev ...
- C# Azure 用Webhook添加警报规则
本篇文章的目的是什么? Azure云端一直困扰着我的是,如果遇到数据库累积数据量过大.数据库DTU过大.应用程序服务访问量过大等,我们都没办法知道他们什么时候过大.只能做的是,我们天天看着我们的应用, ...
- 手把手教你实现自己的abp代码生成器
代码生成器的原理无非就是得到字段相关信息(字段名,字段类型,字段注释等),然后根据模板,其实就是字符串的拼接与替换生成相应代码. 所以第一步我们需要解决如何得到字段的相关信息,有两种方式 通过反射获得 ...
- ASP.NET MVC使用RenderSection渲染节点
几天没有时间做ASP.NET mvc练习,忙于ERP的二次开发.忙里间,想起MVC还有很多基础的知识需要撑握与了解.记得以前有练习过<MVC母版页_Layout.cshtml> http: ...
- C语言Win32 Application 的标题栏图标,任务栏图标,exe文件图标问题
我们这里新建的首先是一个空工程,新建c文件. 因为是空工程,我们没有资源文件,要用到图标资源,首先要新建和导入图标为资源. 选择引入资源,选择要引入的ico文件 完成,重命名保存Script_icon ...