Vous êtes sur la page 1sur 51

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
INI-style

• pytest.ini

• tox.ini

• setup.cfg
Basic configuration
Path

• Current dir

• Parent dir

• ...
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
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
Assertions
Define Own Comparison

def  test_compare():  
       assert  Foo(1)  ==  Foo(2)

>              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 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
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 - 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
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 - modular
class  App(object):  
!
       def  __init__(self,  request):  
               self.request  =  request  
!
@pytest.fixture  
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 - 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)
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
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 - xUnit
def  setup_function(function):  
       print  'setup'  
def  teardown_function(function):  
       print  'teardown'  
def  test_func():  
       print  'func'  
!
#  ==>  
"""  
setup  
func  
teardown  
"""
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  
"""
Fixtures - xUnit

• setup_module / teardown_module

• setup_class / teardown_class

• setup_method / teardown_method

• setup_function / teardown_function
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
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=s
earch
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

Vous aimerez peut-être aussi