Py.test

2,906 views
2,525 views

Published on

A py.test sharing slide.

Published in: Technology

Py.test

  1. 1. py.test git clone https://github.com/soasme/pytest_tutorial
  2. 2. • Basic: example / usage • Fixture: mechanism / builtin • Plugin: conftest / plugin / hook / 3-party • Scale
  3. 3. Basic
  4. 4. Getting start! #  content  of  test_sample.py   def  func(x):          return  x  +  1   ! def  test_answer():          assert  func(3)  ==  5  
  5. 5. #  content  of  test_sysexit.py   import  pytest   def  f():          raise  SystemExit(1)   ! def  test_mytest():          with  pytest.raises(SystemExit):                  f()  
  6. 6. class  TestClass:          def  test_one(self):                  x  =  "this"                  assert  'h'  in  x   !        def  test_two(self):                  x  =  "hello"                  assert  hasattr(x,  'check')  
  7. 7. How to run cases? • py.test tests/test_mod.py • py.test tests/ • py.test -k match # def test_match():
  8. 8. 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
  9. 9. 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
  10. 10. /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
  11. 11. How to run cases? import  pytest   def  test_function():          ...          pytest.set_trace()  
  12. 12. py.test -h
  13. 13. What to test? • folder, file. • recursive • test_xxx.py, xxx_test.py • TestClass (without __init__ method) • all the function or method with prefix `test_`
  14. 14. What to test? #  setup.cfg  /  tox.ini  /  pytest.ini   [pytest]   python_files=check_*.py   python_classes=Check   python_functions=check  
  15. 15. What to test? #  content  of  check_myapp.py   class  CheckMyApp:          def  check_simple(self):                  pass          def  check_complex(self):                  pass  
  16. 16. Basic configuration INI-style • pytest.ini • tox.ini • setup.cfg
  17. 17. Basic configuration Path • Current dir • Parent dir • ...
  18. 18. 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
  19. 19. Assertions • assert expr • assert a == b • self.assertEqual(a, b) • assert expr, “Expected message” • pytest.raises
  20. 20. Assertions • Why `assert`? • simple • nice output • http://pytest.org/latest/example/ reportingdemo.html
  21. 21. Assertions Define Own Comparison #  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)]   Lesson 4
  22. 22. Assertions Define Own Comparison def  test_compare():          assert  Foo(1)  ==  Foo(2) >              assert  f1  ==  f2   E              assert  Comparing  Foo  instances:   E                        vals:  1  !=  2  
  23. 23. Assertions • Py.test refined `assert` statement • Note: `assert expr, msg` won't output traceback
  24. 24. Fixtures • Better than setUp / tearDown: • Explicit name • Call only when needed • Scope: module, class, session, function • Cascade, fixture A => fixture B => ... • Scalability
  25. 25. Fixtures as func args import  pytest   ! @pytest.fixture   def  bookmark(app):          return  Bookmark.create(   user_id=1,   works_id=1)
  26. 26. Fixtures as func args def  test_get_by_relation(bookmark):          bookmarks  =  Bookmark.get(   user_id=1,   works_id=1   )          assert  bookmarks          assert  bookmarks[0].id  ==   bookmark.id Lesson 01
  27. 27. Fixtures as func args • Testcase only care about fixture, no import, no setup, no teardown. • IoC
  28. 28. Fixtures - scope @pytest.fixture(scope="module")   def  smtp():          return  smtplib.SMTP("dou.bz")
  29. 29. Fixtures - finalization @pytest.fixture(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
  30. 30. 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
  31. 31. Fixtures - modular class  App(object):   !        def  __init__(self,  request):                  self.request  =  request   ! @pytest.fixture   def  app(request,                  mc_logger,                  db_logger                  ):          return  App(request)  
  32. 32. 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)
  33. 33. Fixtures - autouse @pytest.fixture   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)
  34. 34. Fixtures - parametrizing @pytest.mark.parametrize(          "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
  35. 35. 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'          ...
  36. 36. Fixtures - xUnit def  setup_function(function):          print  'setup'   def  teardown_function(function):          print  'teardown'   def  test_func():          print  'func'   ! #  ==>   """   setup   func   teardown   """
  37. 37. Fixtures - xUnit class  TestBookmark:          def  setup_method(self,  method):                  print  'setup'          def  teardown_method(self,  method):                  print  'teardown'          def  test_method(self):                  print  'method'   ! #  ==>   """   setup   method   teardown   """
  38. 38. Fixtures - xUnit • setup_module / teardown_module • setup_class / teardown_class • setup_method / teardown_method • setup_function / teardown_function
  39. 39. Fixtures - builtin import  datetime   import  pytest   ! FAKE_TIME  =  datetime.datetime(2020,  12,  25,  17,  05,  55)   ! @pytest.fixture   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
  40. 40. Fixtures - builtin • monkeypatch • tmpdir • capsys / capfd • `py.test --fixture`
  41. 41. 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 !
  42. 42. unittest.TestCase • Compatible • But be careful. There is no funcargs mechanism for unittest cases.
  43. 43. Plugin • py.test supply many hooks. • collection / configuration / run / output • Basic types: • builtin • 3-party plugins • conftest.py plugins
  44. 44. Plugin - find conftest.py • recursive • `import conftest` X
  45. 45. Plugin - 3-party • pip install pytest-xxxxx • pytest-random, pytest-cov • https://pypi.python.org/pypi? %3Aaction=search&term=pytest&submit=s earch
  46. 46. 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"
  47. 47. Plugin - hooks • http://pytest.org/latest/plugins.html#hookspecification-and-validation • see source.
  48. 48. 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."                  )          )
  49. 49. 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/
  50. 50. Plugin - example #  content  of  tests/conftest.py   pytest_plugins  =  "suites.isolated_cases" $ py.test --with-data-service tests/
  51. 51. EOF

×