pytest教程

教程说明:

该pytest框架使编写小型可读测试变得容易,并且可以扩展以支持应用程序和库的复杂功能测试。

pytest 开始使用

pytest需要你已掌握Python,如果还没有点击这里学习Python

安装pytest

pytest需要:Python 3.7+ 或 PyPy3。

1、在命令行中运行以下命令:

pip install -U pytest

2、检查您是否安装了正确的版本:

$ pytest --version
pytest 7.1.0

创建你的第一个测试

创建一个名为 的新文件​test_sample.py​,其中包含一个函数和一个测试:

# content of 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-7.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
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 =============================

[100%] 是指运行所有测试用例的整体进度。 完成后,pytest 会显示失败报告,因为 func(3) 不返回 5。

运行多个测试

pytest将在当前目录及其子目录中运行 ​test_*.py​ 或 ​*_test.py​ 形式的所有文件。

断言引发了某个异常

使用 ​raises ​断言某些代码引发了异常:

# content of 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

将多个测试分组到一个类中

一旦您开发了多个测试,您可能希望将它们分组到一个类中。 pytest 可以很容易地创建一个包含多个测试的类:

# content of 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 按照其 Python 测试约定发现所有测试,因此它会找到两个以 ​test_ ​为前缀的函数。 不需要对任何东西进行子类化,但请确保在您的类前面加上 ​Test ​,否则该类将被跳过。 我们可以通过传递文件名来简单地运行模块:

$ pytest -q test_class.py
.F                                                                   [100%]
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________

self = <test_class.TestClass object at 0xdeadbeef0001>

    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

第一次测试通过,第二次失败。 您可以很容易地看到断言中的中间值,以帮助您了解失败的原因。

将测试分组在类中可能是有益的,原因如下:

  • 测试配置
  • 仅在该特定类中共享用于测试的固定装置
  • 在类级别应用标记,并将它们隐式应用于所有测试

在类中对测试进行分组时需要注意的是,每个测试都有一个唯一的类实例。 让每个测试共享相同的类实例对测试隔离非常不利,并且会促进不良的测试实践。 例如:

# content of test_class_demo.py
class TestClassDemoInstance:
    value = 0

    def test_one(self):
        self.value = 1
        assert self.value == 1

    def test_two(self):
        assert self.value == 1
$ pytest -k TestClassDemoInstance -q
.F                                                                   [100%]
================================= FAILURES =================================
______________________ TestClassDemoInstance.test_two ______________________

self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>

    def test_two(self):
>       assert self.value == 1
E       assert 0 == 1
E        +  where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>.value

test_class_demo.py:9: AssertionError
========================= short test summary info ==========================
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
1 failed, 1 passed in 0.12s

请注意,在类级别添加的属性是类属性,因此它们将在测试之间共享。

为功能测试请求一个唯一的临时目录

pytest提供内置​fixture /function​参数来请求任意资源,比如一个唯一的临时目录:

# content of test_tmp_path.py
def test_needsfiles(tmp_path):
    print(tmp_path)
    assert 0

在测试函数签名中列出名称​tmp_path​, pytest将在执行测试函数调用之前查找并调用一个​fixture​工厂来创建资源。在运行测试之前,pytest会创建一个每个测试调用唯一的临时目录:

$ pytest -q test_tmp_path.py
F                                                                    [100%]
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________

tmp_path = PosixPath('PYTEST_TMPDIR/test_needsfiles0')

    def test_needsfiles(tmp_path):
        print(tmp_path)
>       assert 0
E       assert 0

test_tmp_path.py:3: AssertionError
--------------------------- Captured stdout call ---------------------------
PYTEST_TMPDIR/test_needsfiles0
========================= short test summary info ==========================
FAILED test_tmp_path.py::test_needsfiles - assert 0
1 failed in 0.12s

通过下面的命令来了解内置pytest fixture的类型:

pytest --fixtures   # shows builtin and custom fixtures

注意,除非添加了​-v​选项,否则该命令会省略带有​_​前导的fixture。

领取免费资料

扫描下方二维码或打开微信搜一搜“w3cschool编程狮”关注公众号回复关键词【Python123】或者【Python资料包】免费领取 Python 学习资料,包含软件安装包,电子书、思维导图等



温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }