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肯定是其中的一个理由. 测试数据的准备和执行以后的数 ...
随机推荐
- Flyweight享元模式(结构型模式)
1.面向对象的缺点 虽然OOP能很好的解决系统抽象的问题,并且在大多数的情况下,也不会损失系统的性能.但是在某些特殊的业务下,由于对象的数量太多,采用面向对象会给系统带来难以承受的内存开销.示例代码如 ...
- ajax 提交添加元素内容
JS <script type="text/javascript"> $('.Phone_Interview_Comments').click(function () ...
- windows cmd窗口提示“telnet”命令不能内部或外部命令,也不是可运行的程序
windows cmd窗口提示“telnet”命令不能内部或外部命令,也不是可运行的程序 原因:C:\Windows\System32目录下没有telnet.exe,path系统变量的值包含了C:\W ...
- 修改vs2012 颜色
http://bbs.pcbeta.com/viewthread-1265615-1-1.html VS2012的默认深色主题的确让整个IDE看起来很有气场,而且深色的主题保护眼睛,还是蛮不错的. 但 ...
- 对CAP原理的理解
对CAP原理的理解 CAP原理按照定义,指的是C(Consistency)一致性,A(Availability)可用性,P(Partition tolerance)分区容错性在一个完整的计算机系统中三 ...
- Spark(1.6.1) Sql 编程指南+实战案例分析
首先看看从官网学习后总结的一个思维导图 概述(Overview) Spark SQL是Spark的一个模块,用于结构化数据处理.它提供了一个编程的抽象被称为DataFrames,也可以作为分布式SQL ...
- ThreadLocal剧集(一)
总述 最近做了一个日志调用链路跟踪的项目,涉及到操作标识在线程和子线程,线程池以及远程调用之间的传递问题.最终采用了阿里开源的TransmittableThreadLocal插件(https: ...
- Jmeter接口测试动态传参——动态获取token值
先添加一个线程组,然后在线程组下添加HTTP Request 环境变量: 线程组下添加User Defined Variables 调用变量:${变量名} 添加结果树: 记录登录后的token: 获取 ...
- JS中for循环变量作用域--解决for循环异步执行的问题
被这个问题困惑了很久,终于在网上找到了答案,感谢~ 现在分享给大家~ js中如何让一个for循环走完之后,再去执行下面的语句? 这涉及for循环变量作用域的问题,js中作用域只有函数作用域和全局作用域 ...
- Vue下拉刷新组件
Examples examples Installation npm install vue-pull-to --save Use Setup <template> <div> ...