pytest常见用法总结

2019-05-19  本文已影响0人  利欧leo丶

最近工作中用到了pytest,总结一些用法:

1. 安装:

pip install pytest

2. 运行:

pytest 默认只能识别以test_ 开头的文件和测试用例,如果pytest后面不带文件名,则默认执行当前目录下所有以test_ 开头的文件。

# test_demo.py
def test_01():
    assert 1+1 == 2

def test_02():
    assert 1+3 == 4

执行结果:

$ pytest test_demo.py
========================================= test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items

test_demo.py ..                                                                                      [100%]

======================================== 2 passed in 0.04 seconds =========================================

如果只想执行test_01,可以使用pytest test_demo.py::test_01

# test_class.py
class TestClass(object):
    def test_one(self):
        x = "this"
        assert 'h' in x

    def test_two(self):
        x = "hello"
        assert hasattr(x, 'check')

执行结果:

$ pytest test_class.py
=========================================== test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items

test_class.py .F                                                                                     [100%]

================================================= FAILURES =================================================
____________________________________________ TestClass.test_two ____________________________________________

self = <test_class.TestClass object at 0x102f46780>

    def test_two(self):
        y = "world"
>       assert 'h' in y
E       AssertionError: assert 'h' in 'world'

test_class.py:9: AssertionError
========================================== 1 failed, 1 passed in 0.08 seconds ====================================

如果一个文件里有多个类,你只想执行其中一个类里的用例:
pytest test_class.py::TestClass

# testcase/test_demo01.py
def test_one():
    x = 'this'
    assert 'h' in x

# testcase/test_demo02.py
def test_two():
    y = 'world'
    assert 'h' in y

执行结果:

$ pytest testcase/
========================================== test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items

testcase/test_demo01.py .                                                                            [ 50%]
testcase/test_demo02.py F                                                                            [100%]

============================================== FAILURES ===========================================
_________________________________________________ test_two _________________________________________________

    def test_two():
        y = 'world'
>       assert 'h' in y
E       AssertionError: assert 'h' in 'world'

testcase/test_demo02.py:3: AssertionError
==================================== 1 failed, 1 passed in 0.09 seconds ================================
# test_mark.py
@pytest.mark.smoke
def test_01():
    assert 1+1 == 2

def test_02():
    assert 1+3 == 4
$ pytest -m smoke test_mark.py
=========================================== test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items / 1 deselected / 1 selected

test_mark.py .                                                                                       [100%]

================================== 1 passed, 1 deselected in 0.03 seconds ==================================

可以看到只执行带@pytest.mark.smoke的用例。

$ pytest -k 01 test_mark.py
=========================================== test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items / 1 deselected / 1 selected

test_mark.py .                                                                                       [100%]

================================== 1 passed, 1 deselected in 0.01 seconds ==================================

按照用例名字来执行,只执行名字里含有01的测试用例。

3. pytest fixture

@pytest_fixture的作用是提供一个固定的参数给测试重复的使用,相当于unittest里的setupteardown.

# test_fixture.py
@pytest.fixture(scope="module")
def num():
    n = random.randint(1, 5)
    return n

def test_01(num):
    print(num)
    assert 0

def test_02(num):
    print(num)
    assert 0
$ pytest test_fixture.py
=========================================== test session starts ============================================
platform darwin -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: /Users/libo/python3workspace/learn, inifile:
plugins: rerunfailures-7.0, picked-0.4.1, parallel-0.0.9, forked-1.0.2, cov-2.7.1, allure-pytest-2.6.1
collected 2 items

test_fixture.py FF                                                                                   [100%]

================================================= FAILURES =================================================
_________________________________________________ test_01 __________________________________________________

num = 3

    def test_01(num):
        print(num)
>       assert 0
E       assert 0

test_fixture.py:12: AssertionError
------------------------------------------- Captured stdout call -------------------------------------------
3
_________________________________________________ test_02 __________________________________________________

num = 3

    def test_02(num):
        print(num)
>       assert 0
E       assert 0

test_fixture.py:16: AssertionError
------------------------------------------- Captured stdout call -------------------------------------------
3
========================================= 2 failed in 0.06 seconds =========================================
# conftest.py
import smtplib
import pytest


@pytest.fixture(scope="module")
def smtp_connection():
    smtp_connection = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
    yield smtp_connection  # provide the fixture value
    print("teardown smtp")
    smtp_connection.close()
# 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 purpose
$ pytest -s -q --tb=no test_module.py
FFteardown smtp

2 failed in 6.81 seconds

从上面的运行可以看出来,在执行完两个测试用例之后才调用yield后面的print语句。如果我们把scope改成scope="function"那么fixture的setup和teardown就会在每一个测试用例开始和结束时执行。

import smtplib
import pytest


@pytest.fixture(scope="module")
def smtp_connection():
    with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp_connection:
        yield smtp_connection  # provide the fixture value

4. pytest.mark.parametrize

pytest 内置的pytest.mark.parametrize装饰器支持将测试函数的参数的参数化。

import pytest


@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
    assert eval(test_input) == expected

可以直接通过@pytest.mark.parametrize传递参数,而不需要在测试函数里面通过for循环来实现。

@pytest.mark.parametrize还可以添加起来使用:

import pytest


@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
    assert x + y == 2

上面的例子里会一共有4中情况:x=0/y=2,x=0/y=3,x=1/y=2,x=1/y=3一共四种情况。

更多用法可以参考官方文档.

5. pytest.ini

pytest的主配置文件,可以改变pytest的默认行为。我们可以把经常使用的一些选项放到pytest.ini中,或者在里面添加一些markers。

# pytest.ini 文件
[pytest]
addopts =
    --verbose
    --reruns 5    # 需要安装 pytest-rerunfailures 插件
    --clean-alluredir    # 需要 allure-pytest 插件
    --alluredir=/tmp/allure-results/
markers = 
    smoke: 冒烟测试用例

使用 pytest --help 可以看到常用的pytest.ini选项:

[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:

  markers (linelist)       markers for test functions
  empty_parameter_set_mark (string) default marker for empty parametersets
  norecursedirs (args)     directory patterns to avoid for recursion
  testpaths (args)         directories to search for tests when no files or directories are given in the command line.
  console_output_style (string) console output: classic or with additional progress information (classic|progress).
  usefixtures (args)       list of default fixtures to be used with this project
  python_files (args)      glob-style file patterns for Python test module discovery
  python_classes (args)    prefixes or glob names for Python test class discovery
  python_functions (args)  prefixes or glob names for Python test function and method discovery
  xfail_strict (bool)      default for the strict parameter of xfail markers when not given explicitly (default: False)
  doctest_optionflags (args) option flags for doctests
  doctest_encoding (string) encoding used for doctest files
  cache_dir (string)       cache directory path.
  filterwarnings (linelist) Each line specifies a pattern for warnings.filterwarnings. Processed after -W and --pythonwarnings.
  log_print (bool)         default value for --no-print-logs
  log_level (string)       default value for --log-level
  log_format (string)      default value for --log-format
  log_date_format (string) default value for --log-date-format
  log_cli (bool)           enable log display during test run (also known as "live logging").
  log_cli_level (string)   default value for --log-cli-level
  log_cli_format (string)  default value for --log-cli-format
  log_cli_date_format (string) default value for --log-cli-date-format
  log_file (string)        default value for --log-file
  log_file_level (string)  default value for --log-file-level
  log_file_format (string) default value for --log-file-format
  log_file_date_format (string) default value for --log-file-date-format
  addopts (args)           extra command line options
  minversion (string)      minimally required pytest version
  workers (string)         Set the max num of workers (aka processes) to start (int or "auto" - one per core)
  tests_per_worker (string) Set the max num of concurrent tests for each worker (int or "auto" - split evenly)
上一篇下一篇

猜你喜欢

热点阅读