pytest测试框架

单元测试最初流行是从JUnit,而他的发明者Kent Beck大神的经典名作<测试驱动开发>这本小书却引领了TDD的风潮,产生了xUnit各个语言系列.

初次接触pytest,感觉不像个xUnit,因为既看不到对TestCase的继承,也找不到Setup/Teardown这些建立/销毁函数.当然这些基本功能肯定是支持的.

pytest虽然作为一个Python单元测试框架的扩展版, 但是它丰富的功能和灵活的特性也很适合做功能测试, 其中的精华就是fixtures.

基础

  • 测试类以Test开头
  • 测试方法以test开头

py.test 用法

pytest提供丰富的命令行参数.

pytest -h
# 其他用法
-q, --quiet  
-s  --capture=no   : 默认通过时不会打印print语句
--cache-show
--cache-clear

下面以测试过程为序,展开各过程主要用法.

配置

pytest配置文件: pytest.ini|tox.ini|setup.cfg

收集

pytest.mark

@pytest.mark.webtest

注: 只作用于tests,对fixture无效

命令行测试用例选择:

  • -k EXPRESSION : 按正则选取
  • -m MARKEXPR : 示例 “not (slow or long)”
  • --ignore=path 忽略部分测试集
  • --collectonly 只是收集用例
# 只允许标记webtest的用例
pytest -v -m webtest

# 运行所有除了webtest的用例
pytest -v -m "not webtest"

运行

pytest也支持运行unittest格式的用例.

基本用法:

pytest test_mod.py::TestClass::test_method

命令行辅助选项:

--lf, --last-failed   rerun only the tests that failed at the last run (or all if none failed)

# 退出条件:
-x, --exitfirst 出错后退出
--maxfail=num 失败N次后退出

包含上级模块到包路径

集中方式

# 在根目录创建空文件conftest.py
# 或 python -m pytest tests/
# 或设置环境变量 PYTHONPATH
# 或直接修改代码,添加

import sys, os
testPath = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, testPath + '/../')

报告

# 需要先安装pytest-html插件
py.test --html=report.html

# 命令行选项:
--durations=N         # 显示最慢的执行 (N=0 for all)

Setup/Teardown

尽管pytest支持JUnit类型的Setup/Teardown,但通常推荐使用更灵活的fixture方式.

经典方式的用法:

def setup_module(module):
    print("setting up MODULE {0}".format(module.__name__))

class TestBasic:
    def setup_class(cls):
        print("setting up CLASS {0}".format(cls.__name__))

    def setup_method(self, method):
        print("setting up METHOD {0}".format(method.__name__))

    def test_demo(self):
        assert False

fixture

fixtures通常存放在根目录的conftest.py或子文件夹的conftest.py(可用来覆盖并重新定义).

装饰器标记函数为fixture, 总体上fixtures提供:

  • 单元测试框架的基本功能
  • 依赖注入: 一些共有函数值/帮助函数/Mock等
  • 测试数据参数化
  • 灵活性由不同的作用范围和目录级conftest.py等提供

例子

import pytest
import tempfile
import shutil
import os.path


@pytest.fixture
def temp_dir(request):
    dir = tempfile.mkdtemp()
    print(dir)
    # 使用 yield
    yield dir
    # 之后的语句对应teardown
    shutil.rmtree(dir)


def test_osfiles(temp_dir):
    os.mkdir(os.path.join(temp_dir, "a"))
    os.mkdir(os.path.join(temp_dir, "b"))
    dir_contents = os.listdir(temp_dir)
    assert len(dir_contents) == 2
    assert "a" in dir_contents
    assert "b" in dir_contents

fixture的用法

@pytest.fixture()

主要参数:

  • scope: 生命周期可以为 session/module/class
  • params: 参数化,会执行多次
  • autouse=True

tear down函数体定义:

  • 代码块为yield之后的所有语句
  • 或者使用request.addfinalizer(fin)的方式 (好处:及时发生异常也会执行)

标记或忽略用例

pytest.skip结合if语句 等价于 @pytest.mark.skipif(“sys.version_info <= (3,0)”)

参数化

  • request.params
  • @pytest.mark.parametrize
  • pytest_generate_tests

注:可以用ids参数更新测试名称/override function name

tests之间共享数据

@pytest.fixture(scope="module")
def data():
    return {"key1": None, "key2": "value2"}

test run之间共享数据: cache

# 通过request fixture
request.config.cache.set('shared','a')
assert request.config.cache.get('shared',None) == 'a'

命令行辅助项

  • --fixtures 显示可用的fixture
  • --setup-only only setup fixtures, do not execute tests.
  • --setup-show show setup of fixtures while executing tests.
  • --setup-plan show what fixtures and tests would be executed but don’t execute anything.

内置的fixture

  • tmpdir
  • pytestconfig
  • cache
  • monkeypatch
  • capsys
  • doctest_namespace
  • recwarn
# monkeypatch: mock模块和环境
monkeypatch.setattr()
monkeypatch.delattr()

功能介绍

日志相关

# 命令行参数
--log-level
--log-cli-level

报告

# 生成HTML报告,需插件支持
pytest --html=report.html
# 生成JUnit兼容报告,方便与Jenkins集成
pytest --junitxml=junit-report.xml

扩展资源

流行插件

  • pytest-variables : 通过json文件定义共享变量
  • pytest-timeout: 测试超时插件,避免长时间异常运行
  • pytest-ordering: 指定测试顺序
  • pytest-dependency: 测试依赖关系
  • pytest-xdist : 并行/分布式执行测试
  • pytest-html : HTML测试报告

示例

# 指定执行顺序
# 原理是修改hook: pytest_collection_modifyitems
@pytest.mark,first
@pytest.mark.order#1
@pytest.mark.run(order=1)

# 超时设置
@pytest.mark.timeout(60)

# 依赖
@pytest.mark.dependency(name="b")
@pytest.mark.dependency(name="e", depends=["b", "c"])

文档