安装和入门指南
Python版本: Python 3.6, 3.7, 3.8, 3.9, PyPy3
平台: Linux and Windows
PyPI 包名: pytest
Documentation as PDF: download latest
pytest 是一个测试框架,可以让你轻而易举的构建简单的和可扩展的测试。 测试没有过多的样板代码,一切都是简单易读的。可以在几分钟就写好一个针对你的应用程序或者库的小型单元测试或复杂功能测试。
1.1 安装 pytest
- 在你的命令行中运行下面的命令
译者注:如果你的电脑中存在多个python版本,推荐替换上面命令的pip为pip3pip install -U pytest
- 确认你安装了正确版本的pytest
译者注:上面命令中的 表 示 在 l i n u x 系 统 下 的 普 通 用 户 输 入 命 令 , 使 用 w i n d o w s 的 同 学 直 接 打 开 命 令 与 提 示 符 , 从 表示在linux系统下的普通用户输入命令,使用windows的同学直接打开命令与提示符,从 表示在linux系统下的普通用户输入命令,使用windows的同学直接打开命令与提示符,从符号后面输入命令,在下文中不重复注释了$ pytest --version pytest 6.1.2
1.2 创建你的第一个测试
用四行代码就能创建一个测试函数:
# 创建一个 test_sample.py,在文件中敲入下面的代码
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
这样,一个测试函数就完成了,现在我们需要运行这个测试函数:
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
(continues on next page)
3
pytest Documentation, Release 6.2
(continued from previous page)
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 1 item
test_sample.py F [100%]
================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_sample.py::test_answer - assert 4 == 5
============================ 1 failed in 0.12s =============================
译者注:这里运行pytest命令的时候,cmd的运行路径需要是在py文件处在的位置
这个[100%]表示的是所有测试用例运行的整体进度。在运行完成之后,pytest会显示一个错误报告,因为func(3)的返回值不是5.
注意:你可以使用 assert 这个关键字去验证测试的期望,pytest的内置高级断言关键字会智能的报告断言表达式的值,你就可以避免Junit中内置方法的许多名字。
译者注:在Junit中,判断相等用assertEquals(1, 2),判断是否为True用assertTrue等等方法,判断字符串是否相等和判断数组是否相等的方法也不相同,但是pytest中用一个统一的assert关键字用作断言,这点是相比于Jnit的优势
1.3 运行多个测试
pytest会运行当前目录和子目录中,文件名格式为test_.py或_test.py的文件。事实上,pytest发现测试用例是遵从标准的发现规则的,具体的发现规则我们在23.2中详细讲解。
译者注:新手经常会纠结为什么我写的测试没有被运行?可能原因就在这里。
1.4 断言一个确定的异常发生
使用pytest的raise方法来断言一些代码引发了一个异常:
# test_sysexit.py的内容
import pytest
def f():
raise SystemExit(1)
def test_mytest():
with pytest.raises(SystemExit):
f()
使用“静默”模式执行测试函数:
$ pytest -q test_sysexit.py
. [100%]
1 passed in 0.12s
注意: -q 或 --quiet 参数可以让输出简洁,我们在接下来的例子中会尽量使用这个参数。
1.5 使用class组合多个测试
当你需要开发许多测试的时候,你可能会希望把它们放进一个class中,pytest可以简单的创建一个包含多个测试的class。
# test_class.py的内容
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
pytest会根据发现规则来发现测试用例,在使用class的时候,你无需将其子类化,但是你需要确保你的class是以Test开头的,否则该class下的测试用例会被跳过。我们可以通过在执行命令中指定文件名的方式运行该测试文件:
$ pytest -q test_class.py
.F [100%]
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass object at 0xdeadbeef>
def test_two(self):
x = "hello"
> assert hasattr(x, "check")
E AssertionError: assert False
E + where False = hasattr('hello', 'check')
test_class.py:8: AssertionError
========================= short test summary info ==========================
FAILED test_class.py::TestClass::test_two - AssertionError: assert False
1 failed, 1 passed in 0.12s
第一个测试用例通过了,第二个测试用例失败了。你可以轻易的看到运行过程中的断言中间值以帮助你理解断言失败的原因。
把多个测试用例组织进一个class中有一下几个好处:
- 测试组织
- 在一个特定的class中共享夹具(fixture)
- 在类这个级别上应用标记(marks),并将标记隐式的应用于所有test
译者注:关于夹具和标记的概念我们在后面学习,这里可以简单了解一下,夹具为测试用例提供上下文,标记为测试用例提供分类的能力
需要注意的是,在将测试组织到类中时,每个测试都有一个类的唯一实例。让每个测试共享相同的类实例对测试隔离非常不利,并且会促进糟糕的测试实践。这一点概述如下:
# test_class_demo.py
class TestClassDemoInstance:
def test_one(self):
assert 0
def test_two(self):
assert 0
$ pytest -k TestClassDemoInstance -q
FF [100%]
================================= FAILURES =================================
______________________ TestClassDemoInstance.test_one ______________________
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef>
def test_one(self):
> assert 0
E assert 0
test_class_demo.py:3: AssertionError
______________________ TestClassDemoInstance.test_two ______________________
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef>
def test_two(self):
> assert 0
E assert 0
test_class_demo.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_class_demo.py::TestClassDemoInstance::test_one - assert 0
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0
2 failed in 0.12s
译者注:使用-k可以指定类名,单独运行某一个类的测试
1.6 为功能测试请求一个唯一的临时目录
pytest提供 内置夹具/函数参数 这种机制来请求任意资源,比如一个唯一的临时目录:
# test_tmpdir.py
def test_needsfiles(tmpdir):
print(tmpdir)
assert 0
译者注:如果式顺序看文档的情况下这里可能看不懂文档在说什么,这里提供的所谓 内置夹具/函数参数 的机制,我们要学习了夹具(fixture)就能理解了,这里我们可以理解这个例子为:在我们写测试函数的时候,可以使用一些默认的参数名,这些参数给我们提供了一些扩展功能,比如上文中的tmpdir就是给这个用例提供了一个临时目录,既然是内置的参数名,就不能随便写了,如果我们将tmpdir写成tempdir,就得不到下面的测试结果了
当你在测试函数的签名中列出了tmpdir这个参数的时候,pytest会在调用测试之前寻找和调用夹具工厂来创建我们所需的资源。在测试执行之前,pytest创建了一个唯一的,一次性调用的临时目录。
$ pytest -q test_tmpdir.py
F [100%]
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________
(continues on next page)
6 Chapter 1. Installation and Getting Started
pytest Documentation, Release 6.2
(continued from previous page)
tmpdir = local('PYTEST_TMPDIR/test_needsfiles0')
def test_needsfiles(tmpdir):
print(tmpdir)
> assert 0
E assert 0
test_tmpdir.py:3: AssertionError
--------------------------- Captured stdout call ---------------------------
PYTEST_TMPDIR/test_needsfiles0
========================= short test summary info ==========================
FAILED test_tmpdir.py::test_needsfiles - assert 0
1 failed in 0.12s
可以在 临时目录和文件 一节中找到更多关于tmpdir使用的信息。
可以通过在命令行中使用下面的命令查询pytest内置夹具
pytest --fixtures # 显示内置夹具和用户夹具
注意:这个命令查询的内容省略了以下划线开头的夹具,我们可以使用-v参数来让命令显示所有的夹具。
1.7 延申阅读
参阅额外的资源可以帮助你为自己特定的工作流构建测试:
- 通过 python -m pytest 命令调用的例子
- 对已有的测试套件使用pytest
- 用属性标记测试函数
- pytest夹具
- 编写插件
- 良好的集成实践
译者注:这里需要延申阅读的都是下面几章的一些知识,我们就不做详细解释了,后面都会讲到