第1章 快速入门
什么是pytest?
pytest是一个强大的Python测试工具,它可以用于所有类型和级别的软件测试。 Pytest可以被开发团队,QA团队,独立测试小组,实践TDD的个人和开放源代码项目。实际上,整个互联网上的项目都是从unittest或者nose转向pytest,包括Mozilla和Dropbox。为什么?因为pytest提供强大的功能,如'断言'重写,第三方插件模型,强大但简单的fixture模型。
pytest是软件测试框架, 也是命令行工具。它会自动找到你写的测试,运行测试并报告结果。可编写插件或安装第三方来扩展插件。它可以用来测试Python发行版。它很容易与其他工具对接,如持续集成和网页自动化。
Pytest脱颖而出的原因:
简单
易读
用assert来测试失败,而不是self.assertEqual() 或者self.assertLessThan()
可运行unittest或nose测试。
事实上很多自动化测试平台,底层就是用驱动的。它们用flask或django等提供友好的页面展示,但是核心层还是用pytest和一些测试库的开发。
本文基于 ubuntu 20, python3.8书写,但是在其他平台通常也应该可以执行。
安装
# pip install pytest
...
$ pytest -h # 查看帮助
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
positional arguments:
file_or_dir
general:
-k EXPRESSION only run tests which match the given substring expression. An expression is a python evaluatable expression
where all names are substring-matched against test names and their parent classes. Example: -k 'test_method
or test_other' matches all test functions and classes whose name contains 'test_method' or 'test_other',
while -k 'not test_method' matches those that don't contain 'test_method' in their names. -k 'not
test_method and not test_other' will eliminate the matches. Additionally keywords are matched to classes
and functions containing extra names in their 'extra_keyword_matches' set, as well as functions which have
names assigned directly to them. The matching is case-insensitive.
-m MARKEXPR only run tests matching given mark expression.
For example: -m 'mark1 and not mark2'.
--markers show markers (builtin, plugin and per-project ones).
-x, --exitfirst exit instantly on first error or failed test.
--fixtures, --funcargs
show available fixtures, sorted by plugin appearance (fixtures with leading '_' are only shown with '-v')
--fixtures-per-test show fixtures per test
--pdb start the interactive Python debugger on errors or KeyboardInterrupt.
--pdbcls=modulename:classname
start a custom interactive Python debugger on errors. For example:
--pdbcls=IPython.terminal.debugger:TerminalPdb
--trace Immediately break when running each test.
--capture=method per-test capturing method: one of fd|sys|no|tee-sys.
-s shortcut for --capture=no.
--runxfail report the results of xfail tests as if they were not marked
--lf, --last-failed rerun only the tests that failed at the last run (or all if none failed)
--ff, --failed-first run all tests, but run the last failures first.
This may re-order tests and thus lead to repeated fixture setup/teardown.
--nf, --new-first run tests from new files first, then the rest of the tests sorted by file mtime
--cache-show=[CACHESHOW]
show cache contents, don't perform collection or tests. Optional argument: glob (default: '*').
--cache-clear remove all cache contents at start of test run.
--lfnf={all,none}, --last-failed-no-failures={all,none}
which tests to run with no previously (known) failures.
--sw, --stepwise exit on test failure and continue from last failing test next time
--stepwise-skip ignore the first failing test but stop on the next failing test
reporting:
--durations=N show N slowest setup/test durations (N=0 for all).
--durations-min=N Minimal duration in seconds for inclusion in slowest list. Default 0.005
-v, --verbose increase verbosity.
--no-header disable header
--no-summary disable summary
-q, --quiet decrease verbosity.
--verbosity=VERBOSE set verbosity. Default is 0.
-r chars show extra test summary info as specified by chars: (f)ailed, (E)rror, (s)kipped, (x)failed, (X)passed,
(p)assed, (P)assed with output, (a)ll except passed (p/P), or (A)ll. (w)arnings are enabled by default (see
--disable-warnings), 'N' can be used to reset the list. (default: 'fE').
--disable-warnings, --disable-pytest-warnings
disable warnings summary
-l, --showlocals show locals in tracebacks (disabled by default).
--tb=style traceback print mode (auto/long/short/line/native/no).
--show-capture={no,stdout,stderr,log,all}
Controls how captured stdout/stderr/log is shown on failed tests. Default is 'all'.
--full-trace don't cut any tracebacks (default is to cut).
--color=color color terminal output (yes/no/auto).
--code-highlight={yes,no}
Whether code should be highlighted (only if --color is also enabled)
--pastebin=mode send failed|all info to bpaste.net pastebin service.
--junit-xml=path create junit-xml style report file at given path.
--junit-prefix=str prepend prefix to classnames in junit-xml output
pytest-warnings:
-W PYTHONWARNINGS, --pythonwarnings=PYTHONWARNINGS
set which warnings to report, see -W option of python itself.
--maxfail=num exit after first num failures or errors.
--strict-config any warnings encountered while parsing the `pytest` section of the configuration file raise errors.
--strict-markers, --strict
markers not registered in the `markers` section of the configuration file raise errors.
-c file load configuration from `file` instead of trying to locate one of the implicit configuration files.
--continue-on-collection-errors
Force test execution even if collection errors occur.
--rootdir=ROOTDIR Define root directory for tests. Can be relative path: 'root_dir', './root_dir', 'root_dir/another_dir/';
absolute path: '/home/user/root_dir'; path with variables: '$HOME/root_dir'.
collection:
--collect-only, --co only collect tests, don't execute them.
--pyargs try to interpret all arguments as python packages.
--ignore=path ignore path during collection (multi-allowed).
--ignore-glob=path ignore path pattern during collection (multi-allowed).
--deselect=nodeid_prefix
deselect item (via node id prefix) during collection (multi-allowed).
--confcutdir=dir only load conftest.py's relative to specified dir.
--noconftest Don't load any conftest.py files.
--keep-duplicates Keep duplicate tests.
--collect-in-virtualenv
Don't ignore tests in a local virtualenv directory
--import-mode={prepend,append,importlib}
prepend/append to sys.path when importing test modules and conftest files, default is to prepend.
--doctest-modules run doctests in all .py modules
--doctest-report={none,cdiff,ndiff,udiff,only_first_failure}
choose another output format for diffs on doctest failure
--doctest-glob=pat doctests file matching pattern, default: test*.txt
--doctest-ignore-import-errors
ignore doctest ImportErrors
--doctest-continue-on-failure
for a given doctest, continue to run after the first failure
test session debugging and configuration:
--basetemp=dir base temporary directory for this test run.(warning: this directory is removed if it exists)
-V, --version display pytest version and information about plugins.When given twice, also display information about
plugins.
-h, --help show help message and configuration info
-p name early-load given plugin module name or entry point (multi-allowed).
To avoid loading of plugins, use the `no:` prefix, e.g. `no:doctest`.
--trace-config trace considerations of conftest.py files.
--debug store internal tracing debug information in 'pytestdebug.log'.
-o OVERRIDE_INI, --override-ini=OVERRIDE_INI
override ini option with "option=value" style, e.g. `-o xfail_strict=True -o cache_dir=cache`.
--assert=MODE Control assertion debugging tools.
'plain' performs no assertion debugging.
'rewrite' (the default) rewrites assert statements in test modules on import to provide assert expression
information.
--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.
logging:
--log-level=LEVEL level of messages to catch/display.
Not set by default, so it depends on the root/parent log handler's effective level, where it is "WARNING"
by default.
--log-format=LOG_FORMAT
log format as used by the logging module.
--log-date-format=LOG_DATE_FORMAT
log date format as used by the logging module.
--log-cli-level=LOG_CLI_LEVEL
cli logging level.
--log-cli-format=LOG_CLI_FORMAT
log format as used by the logging module.
--log-cli-date-format=LOG_CLI_DATE_FORMAT
log date format as used by the logging module.
--log-file=LOG_FILE path to a file when logging will be written to.
--log-file-level=LOG_FILE_LEVEL
log file logging level.
--log-file-format=LOG_FILE_FORMAT
log format as used by the logging module.
--log-file-date-format=LOG_FILE_DATE_FORMAT
log date format as used by the logging module.
--log-auto-indent=LOG_AUTO_INDENT
Auto-indent multiline messages passed to the logging module. Accepts true|on, false|off or an integer.
[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.
filterwarnings (linelist):
Each line specifies a pattern for warnings.filterwarnings. Processed after -W/--pythonwarnings.
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
disable_test_id_escaping_and_forfeit_all_rights_to_community_support (bool):
disable string escape non-ascii characters, might cause unwanted side effects(use at your own risk)
console_output_style (string):
console output: "classic", or with additional progress information ("progress" (percentage) | "count").
xfail_strict (bool): default for the strict parameter of xfail markers when not given explicitly (default: False)
enable_assertion_pass_hook (bool):
Enables the pytest_assertion_pass hook.Make sure to delete any previously generated pyc cache files.
junit_suite_name (string):
Test suite name for JUnit report
junit_logging (string):
Write captured log messages to JUnit report: one of no|log|system-out|system-err|out-err|all
junit_log_passing_tests (bool):
Capture log information for passing tests to JUnit report:
junit_duration_report (string):
Duration time to report: one of total|call
junit_family (string):
Emit XML for schema: one of legacy|xunit1|xunit2
doctest_optionflags (args):
option flags for doctests
doctest_encoding (string):
encoding used for doctest files
cache_dir (string): cache directory path.
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
log_auto_indent (string):
default value for --log-auto-indent
faulthandler_timeout (string):
Dump the traceback of all threads if a test takes more than TIMEOUT seconds to finish.
addopts (args): extra command line options
minversion (string): minimally required pytest version
required_plugins (args):
plugins that must be present for pytest to run
environment variables:
PYTEST_ADDOPTS extra command line options
PYTEST_PLUGINS comma-separated plugins to load during startup
PYTEST_DISABLE_PLUGIN_AUTOLOAD set to disable plugin auto-loading
PYTEST_DEBUG set to enable debug tracing of pytest's internals
to see available markers type: pytest --markers
to see available fixtures type: pytest --fixtures
(shown according to specified file_or_dir or current dir if not specified; fixtures with leading '_' are only shown with the '-v' option
快速入门
def test_passing():
assert (1, 2, 3) == (1, 2, 3)
执行:
$ pytest pass_test.py
======================================================= test session starts =======================================================
platform linux -- Python 3.8.3, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch1
collected 1 item
pass_test.py . [100%]
======================================================== 1 passed in 0.04s ========================================================
pass_test.py后的点表示一个测试运行并通过。 如果你需要更多信息,您可以使用-v或--verbose
在彩色终端,PASSED和底线是绿色的。
def test_failing():
assert (1, 2, 3) == (3, 2, 1)
执行:
如果没有参数,pytest会查看当前目录和所有子目录的测试文件(test_开头或者_test结尾)并运行。 也可以指定文件名,目录名称或这些名称的列表。
我们创建tasks的子目录,增加几个测试
task1_test.py
from collections import namedtuple
Task = namedtuple('Task', ['summary', 'owner', 'done', 'id'])
Task.__new__.__defaults__ = (None, None, False, None)
def test_defaults():
"""Using no parameters should invoke defaults."""
t1 = Task()
t2 = Task(None, None, False, None)
assert t1 == t2
def test_member_access():
"""Check .field functionality of namedtuple."""
t = Task('buy milk', 'brian')
assert t.summary == 'buy milk'
assert t.owner == 'brian'
assert (t.done, t.id) == (False, None)
task2_test.py
from collections import namedtuple
Task = namedtuple('Task', ['summary', 'owner', 'done', 'id'])
Task.__new__.__defaults__ = (None, None, False, None)
def test_asdict():
"""_asdict() should return a dictionary."""
t_task = Task('do something', 'okken', True, 21)
t_dict = t_task._asdict()
expected = {'summary': 'do something',
'owner': 'okken',
'done': True,
'id': 21}
assert t_dict == expected
def test_replace():
"""replace() should change passed in fields."""
t_before = Task('finish book', 'brian', False)
t_after = t_before._replace(id=10, done=True)
t_expected = Task('finish book', 'brian', True, 10)
assert t_after == t_expected
执行示例:
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest
=========================================== test session starts ===========================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items
fail_test.py F [ 16%]
pass_test.py . [ 33%]
tasks/task1_test.py .. [ 66%]
tasks/task2_test.py .. [100%]
================================================ FAILURES =================================================
______________________________________________ test_failing _______________________________________________
def test_failing():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Use -v to get the full diff
fail_test.py:2: AssertionError
=================================== 1 failed, 5 passed in 0.04 seconds ====================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest tasks
=========================================== test session starts ===========================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .. [100%]
======================================== 4 passed in 0.02 seconds =========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest -v tasks/task2_test.py::test_asdict
=========================================== test session starts ===========================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 1 item
tasks/task2_test.py::test_asdict PASSED [100%]
======================================== 1 passed in 0.01 seconds =========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest --collect-only
=========================================== test session starts ===========================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items
<Module 'fail_test.py'>
<Function 'test_failing'>
<Module 'pass_test.py'>
<Function 'test_passing'>
<Module 'tasks/task1_test.py'>
<Function 'test_defaults'>
<Function 'test_member_access'>
<Module 'tasks/task2_test.py'>
<Function 'test_asdict'>
<Function 'test_replace'>
====================================== no tests ran in 0.02 seconds =======================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest --collect-only -k "asdict or defaults"
=========================================== test session starts ===========================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items / 4 deselected
<Module 'tasks/task1_test.py'>
<Function 'test_defaults'>
<Module 'tasks/task2_test.py'>
<Function 'test_asdict'>
====================================== 4 deselected in 0.02 seconds =======================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest -k "asdict or defaults"
=========================================== test session starts ===========================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items / 4 deselected
tasks/task1_test.py . [ 50%]
tasks/task2_test.py . [100%]
================================= 2 passed, 4 deselected in 0.02 seconds ==================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
发现规则小结
- 测试文件应该命名为test_<something>.py或<something>_test.py
- 测试方法和函数应该被命名为test_<something>。
- 测试类应该被命名为Test<Something>
结果类型:
以下是测试功能的可能结果:
- PASSED (.):测试成功。
- FAILED (F):测试失败(或XPASS + strict)。
- SKIPPED (s): 测试被跳过。 你可以使用@pytest.mark.skip()或 pytest.mark.skipif()修饰器告诉pytest跳过测试
- xfail (x):预期测试失败。@pytest.mark.xfail()
- XPASS (X):测试不应该通过。
- ERROR (E):错误
更多选项
- marker 标签
比如只执行test_replace()和test_member_access()
import pytest
...
@pytest.mark.run_these_please
def test_member_access():
...
执行
$ cd /path/to/code/ch1/tasks
pytest -v -m run_these_please
$
================== test session starts ===================
collected 4 items
task2.py::test_replace PASSED
task1.py::test_member_access PASSED
=================== 2 tests deselected ===================
========= 2 passed, 2 deselected in 0.02 seconds =========
更多执行方法:-m "mark1 and mark2"、 -m "mark1 and not mark2"、-m "mark1 or mark2"
-
-x, –exitfirst 失败后停止执行
首次失败后停止执行:py.test -x
py.test --maxfail=2 两次失败之后停止执行
$ pytest -x
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items
fail_test.py F
====================================================== FAILURES =======================================================
____________________________________________________ test_failing _____________________________________________________
def test_failing():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Use -v to get the full diff
fail_test.py:2: AssertionError
============================================== 1 failed in 0.04 seconds ===============================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
1$ pytest --tb=no
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items
fail_test.py F [ 16%]
pass_test.py . [ 33%]
tasks/task1_test.py .. [ 66%]
tasks/task2_test.py .. [100%]
========================================= 1 failed, 5 passed in 0.05 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
$ pytest --maxfail=1 --tb=no
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items
fail_test.py F
============================================== 1 failed in 0.04 seconds ===============================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest --maxfail=2 --tb=no
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items
fail_test.py F [ 16%]
pass_test.py . [ 33%]
tasks/task1_test.py .. [ 66%]
tasks/task2_test.py .. [100%]
========================================= 1 failed, 5 passed in 0.04 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
- 设置捕捉
默认捕捉方式为file descriptor (FD)级捕捉。捕捉所有到操作系统的1,2输出。
syslevel级捕捉只捕捉python的sys.stdout和sys.stderr。
py.test -s # disable all capturing 实际为--capture=no这样print就可以在屏幕输出。
py.test --capture=sys # replace sys.stdout/stderr with in-mem files
py.test --capture=fd # also point filedescriptors 1 and 2 to temp file
- --lf, --last-failed 执行上次失败的测试
多在--tb 之后使用
--ff / --failed-first则会先执行失败的,然后执行成功的。
$ pytest --lf
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items / 5 deselected
run-last-failure: rerun previous 1 failure
fail_test.py F [100%]
====================================================== FAILURES =======================================================
____________________________________________________ test_failing _____________________________________________________
def test_failing():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Use -v to get the full diff
fail_test.py:2: AssertionError
======================================= 1 failed, 5 deselected in 0.04 seconds ========================================
$ pytest --ff --tb=no
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 6 items
run-last-failure: rerun previous 1 failure first
fail_test.py F [ 16%]
pass_test.py . [ 33%]
tasks/task1_test.py .. [ 66%]
tasks/task2_test.py .. [100%]
========================================= 1 failed, 5 passed in 0.04 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
- -q 静默模式
-q, --quiet decrease verbosity.
$ pytest -q
F..... [100%]
====================================================== FAILURES =======================================================
____________________________________________________ test_failing _____________________________________________________
def test_failing():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Full diff:
E - (1, 2, 3)
E ? ^ ^
E + (3, 2, 1)
E ? ^ ^
fail_test.py:2: AssertionError
1 failed, 5 passed in 0.04 seconds
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest -qq
F..... [100%]
====================================================== FAILURES =======================================================
____________________________________________________ test_failing _____________________________________________________
def test_failing():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Full diff:
E - (1, 2, 3)
E ? ^ ^
E + (3, 2, 1)
E ? ^ ^
fail_test.py:2: AssertionError
- -l 在traceback中显示本地变量
--showlocals 在traceback中显示本地变量
修改test_replace()中的t_expected = Task( 'finish book' , 'brian' , True, 10)为t_expected = Task( 'finish book' , 'brian' , True, 11)
py.test --showlocals 在traceback中显示本地变量
py.test -l 在traceback中显示本地变量(快捷方式)
$ pytest tasks
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .F [100%]
====================================================== FAILURES =======================================================
____________________________________________________ test_replace _____________________________________________________
def test_replace():
"""replace() should change passed in fields."""
t_before = Task('finish book', 'brian', False)
t_after = t_before._replace(id=10, done=True)
t_expected = Task('finish book', 'brian', True, 11)
> assert t_after == t_expected
E AssertionError: assert Task(summary=...e=True, id=10) == Task(summary='...e=True, id=11)
E At index 3 diff: 10 != 11
E Use -v to get the full diff
tasks/task2_test.py:26: AssertionError
========================================= 1 failed, 3 passed in 0.04 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest tasks -l
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .F [100%]
====================================================== FAILURES =======================================================
____________________________________________________ test_replace _____________________________________________________
def test_replace():
"""replace() should change passed in fields."""
t_before = Task('finish book', 'brian', False)
t_after = t_before._replace(id=10, done=True)
t_expected = Task('finish book', 'brian', True, 11)
> assert t_after == t_expected
E AssertionError: assert Task(summary=...e=True, id=10) == Task(summary='...e=True, id=11)
E At index 3 diff: 10 != 11
E Use -v to get the full diff
t_after = Task(summary='finish book', owner='brian', done=True, id=10)
t_before = Task(summary='finish book', owner='brian', done=False, id=None)
t_expected = Task(summary='finish book', owner='brian', done=True, id=11)
tasks/task2_test.py:26: AssertionError
========================================= 1 failed, 3 passed in 0.04 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
- –tb=style
py.test -l 在traceback中显示本地变量(快捷方式)
py.test --tb=auto 默认格式,首尾为long,其他为short
py.test --tb=long 详细的traceback信息格式化形式
py.test --tb=native 标准库格式化形式, 没有额外信息
py.test --tb=short 更短的traceback格式
py.test --tb=line 每个错误一行
py.test --tb=no 无traceback
py.test --full-trace 最详细的格式
实例:
$ pytest tasks --tb no
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .F [100%]
========================================= 1 failed, 3 passed in 0.04 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest tasks --tb line
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .F [100%]
====================================================== FAILURES =======================================================
/home/andrew/code/backup/pytest_testing/ch1/tasks/task2_test.py:26: AssertionError: assert Task(summary=...e=True, id=10) == Task(summary='...e=True, id=11)
========================================= 1 failed, 3 passed in 0.03 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest tasks --tb short
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .F [100%]
====================================================== FAILURES =======================================================
____________________________________________________ test_replace _____________________________________________________
tasks/task2_test.py:26: in test_replace
assert t_after == t_expected
E AssertionError: assert Task(summary=...e=True, id=10) == Task(summary='...e=True, id=11)
E At index 3 diff: 10 != 11
E Use -v to get the full diff
========================================= 1 failed, 3 passed in 0.04 seconds ==========================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ vi tasks/task2_test.py
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest tasks --duration=3
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .. [100%]
============================================== slowest 3 test durations ===============================================
0.00s setup tasks/task1_test.py::test_defaults
0.00s setup tasks/task2_test.py::test_asdict
0.00s setup tasks/task2_test.py::test_replace
============================================== 4 passed in 0.02 seconds ===============================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
- –durations=N
统计最慢执行时间
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$ pytest tasks --duration=3
================================================= test session starts =================================================
platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/andrew/code/backup/pytest_testing/ch1, inifile:
collected 4 items
tasks/task1_test.py .. [ 50%]
tasks/task2_test.py .. [100%]
============================================== slowest 3 test durations ===============================================
0.00s setup tasks/task1_test.py::test_defaults
0.00s setup tasks/task2_test.py::test_asdict
0.00s setup tasks/task2_test.py::test_replace
============================================== 4 passed in 0.02 seconds ===============================================
andrew@andrew-PowerEdge-T630:~/code/backup/pytest_testing/ch1$
参考资料
- 本文涉及的python测试开发库 谢谢点赞!
- 本文相关书籍下载
- 代码地址