Upload
soasme
View
1.257
Download
0
Embed Size (px)
DESCRIPTION
A py.test sharing slide.
Citation preview
py.test
git clone https://github.com/soasme/pytest_tutorial
• Basic: example / usage
• Fixture: mechanism / builtin
• Plugin: conftest / plugin / hook / 3-party
• Scale
Basic
Getting start!
# content of test_sample.py def func(x): return x + 1 !
def test_answer(): assert func(3) == 5
# content of test_sysexit.py import pytest def f(): raise SystemExit(1) !
def test_mytest(): with pytest.raises(SystemExit): f()
class TestClass: def test_one(self): x = "this" assert 'h' in x !
def test_two(self): x = "hello" assert hasattr(x, 'check')
How to run cases?
• py.test tests/test_mod.py
• py.test tests/
• py.test -k match # def test_match():
How to run cases?
• py.test --showlocals # trace context
• py.test -x # stop on first failure case
• py.test --maxfail=2 # on the second
• py.test -s # enable `print` output
• py.test --durations=10 # list top10 slowest cases
How to run cases?
• py.test --tb=long # default traceback
• py.test --tb=line # oneline
• py.test --tb=short
• py.test --tb=native # Python default traceback
/tmp % py.test test_a.py --tb=line --pdb >>>> traceback >>>> E assert 1 != 1 >>>>> entering PDB >>>> > /private/tmp/test_a.py(10)test_one() -> assert num != 1 (Pdb) num 1 (Pdb) exit
How to run cases?
import pytest def test_function(): ... pytest.set_trace()
py.test -h
What to test?
• folder, file.
• recursive
• test_xxx.py, xxx_test.py
• TestClass (without __init__ method)
• all the function or method with prefix `test_`
What to test?
# setup.cfg / tox.ini / pytest.ini [pytest] python_files=check_*.py python_classes=Check python_functions=check
What to test?
# content of check_myapp.py class CheckMyApp: def check_simple(self): pass def check_complex(self): pass
Basic configuration
• pytest.ini
• tox.ini
• setup.cfg
INI-style
Basic configuration
• Current dir
• Parent dir
• ...
Path
Basic configuration# content of pytest.ini # (or tox.ini or setup.cfg) [pytest] addopts = -‐-‐tb=short -‐x
py.test test_module.py -k test_func
Assertions
• assert expr
• assert a == b
• self.assertEqual(a, b)
• assert expr, “Expected message”
• pytest.raises
Assertions
• Why `assert`?
• simple
• nice output
• http://pytest.org/latest/example/reportingdemo.html
Assertions
# content of conftest.py def pytest_assertrepr_compare(op, left, right): if (isinstance(left, Foo)
and isinstance(right, Foo) and op == "=="):
return ['Comparing Foo instances:', 'vals: {0.val} != {1.val}'.format(left, right)]
Define Own Comparison
Lesson 4
Assertions
def test_compare(): assert Foo(1) == Foo(2)
Define Own Comparison
> assert f1 == f2 E assert Comparing Foo instances: E vals: 1 != 2
Assertions
• Py.test refined `assert` statement
• Note: `assert expr, msg` won't output traceback
Fixtures
• Better than setUp / tearDown:
• Explicit name
• Call only when needed
• Scope: module, class, session, function
• Cascade, fixture A => fixture B => ...
• Scalability
Fixtures as func args
import pytest !
@pytest.fixture def bookmark(app): return Bookmark.create(
user_id=1, works_id=1)
Fixtures as func argsdef test_get_by_relation(bookmark): bookmarks = Bookmark.get(
user_id=1, works_id=1 )
assert bookmarks assert bookmarks[0].id == bookmark.id
Lesson 01
Fixtures as func args
• Testcase only care about fixture, no import, no setup, no teardown.
• IoC
Fixtures - scope
@pytest.fixture(scope="module") def smtp(): return smtplib.SMTP("dou.bz")
Fixtures - [email protected](scope="session") def database(request): db_name = "{}.db".format(time()) deferred_db.init(db_name) def finalizer(): if os.path.exists(db_name): os.remove(db_name) request.addfinalizer(finalizer) return deferred_db
Lesson 2
Fixtures - parametrizing
@pytest.fixture(params=[ '/', '/reader/', ]) def signed_page(request): return requests.get(request.param) !def test_fetch_pages_success_in_signed(signed_page): assert signed_page.status_code < 300
Lesson 3.1
Fixtures - modularclass App(object): ! def __init__(self, request): self.request = request [email protected] def app(request, mc_logger, db_logger ): return App(request)
Fixtures - autouse
class TestClass: @pytest.fixture(autouse=True) def table(self, database): Table.create_table() !
def test_select(self): assert not Table.get(id=1)
Fixtures - [email protected] def table(request, database): Table.create_table() request.addfinilizer( Table.drop_table) !
@pytest.mark.usefixtures('table') class TestClass: def test_select(self): assert not Table.get(id=1)
Fixtures - [email protected]( "input,expected", [ ("3+5", 8), ("2+4", 6), ("6*9", 42), pytest.mark.xfail(("6*9", 42)) ]) def test_eval(input, expected): assert eval(input) == expected
Lesson 3.2
Fixtures - parametrizing# conftest.py import pytest !def pytest_generate_tests(metafunc): if 'payload' in metafunc.fixturenames: metafunc.parametrize('payload', ['/tmp/test.json', ]) !# test file def test_meta(payload): assert payload == '/tmp/test.json' ...
Fixtures - xUnitdef setup_function(function): print 'setup' def teardown_function(function): print 'teardown' def test_func(): print 'func' !# ==> """ setup func teardown """
Fixtures - xUnitclass TestBookmark: def setup_method(self, method): print 'setup' def teardown_method(self, method): print 'teardown' def test_method(self): print 'method' !# ==> """ setup method teardown """
Fixtures - xUnit
• setup_module / teardown_module
• setup_class / teardown_class
• setup_method / teardown_method
• setup_function / teardown_function
Fixtures - builtinimport datetime import pytest !FAKE_TIME = datetime.datetime(2020, 12, 25, 17, 05, 55) [email protected] def patch_datetime_now(monkeypatch): ! class mydatetime: @classmethod def now(cls): return FAKE_TIME ! monkeypatch.setattr(datetime, 'datetime', mydatetime) !!def test_patch_datetime(patch_datetime_now): assert datetime.datetime.now() == FAKE_TIME
Fixtures - builtin
• monkeypatch
• tmpdir
• capsys / capfd
• `py.test --fixture`
Maker• pytest.marker
• py.test --marker
• marker is like tag.
• @pytest.mark.skipif(getenv('qaci'))
• @pytest.mark.xfail('oooops')
• @pytest.mark.skipif("config.getvalue('pass')")
• @pytest.mark.ask_sunyi
!
unittest.TestCase
• Compatible
• But be careful. There is no funcargs mechanism for unittest cases.
Plugin
• py.test supply many hooks.
• collection / configuration / run / output
• Basic types:
• builtin
• 3-party plugins
• conftest.py plugins
Plugin - find conftest.py
• recursive
• `import conftest` X
Plugin - 3-party
• pip install pytest-xxxxx
• pytest-random, pytest-cov
• https://pypi.python.org/pypi?%3Aaction=search&term=pytest&submit=search
Plugin - load plugin
• py.test -p plugin_name
• py.test -p no:plugin_name
• pytest.ini
• conftest.py `pytest_plugins`
• pytest_plugins = "name1", "name2",
• pytest_plugins = "suites.isolated_cases"
Plugin - hooks
• http://pytest.org/latest/plugins.html#hook-specification-and-validation
• see source.
Plugin - example# content of suites.isolated_cases def pytest_addoption(parser): group = parser.getgroup("isolated_cases", "") group._addoption( '-‐-‐with-‐data-‐service', action="store_true", default=False, dest='with_data_service', help=( "with MySQL/beansdb/memcached up at the beginning of session" "and down at the end of session." ) )
Plugin - example
# content of isolated_cases def pytest_configure(config): if config.option.with_data_service: build_tables() stop_kvstore() sleep(1) start_kvstore()
$ py.test --with-data-service tests/
Plugin - example
# content of tests/conftest.py pytest_plugins = "suites.isolated_cases"
$ py.test --with-data-service tests/
EOF