æ»ã 次㞠
ãã¹ããã¯ã©ã¹ãã¢ãžã¥ãŒã«ããã£ã¬ã¯ããªã«æŽçããæ¹æ³ãåŠã³ãŸãã 次ã«ãããŒã«ãŒã䜿çšããŠå®è¡ãããã¹ããããŒã¯ããæ¹æ³ã瀺ããçµã¿èŸŒã¿ããŒã«ãŒãã©ã®ããã«ãã¹ããã¹ãããããŠãã¹ããããŒã¯ãã倱æãæåŸ
ã§ãããã«ã€ããŠèª¬æããŸãã æåŸã«ããã¹ãã®ãã©ã¡ãŒã¿ãŒåã«ã€ããŠèª¬æããŸããããã«ãããç°ãªãããŒã¿ã§ãã¹ããåŒã³åºãããšãã§ããŸãã

ãã®æ¬ã®äŸã¯ãPython 3.6ãšpytest 3.2ã䜿çšããŠæžãããŠããŸãã pytest 3.2ã¯ãPython 2.6ã2.7ãããã³Python 3.3+ããµããŒãããŠããŸãã
Tasksãããžã§ã¯ãã®ãœãŒã¹ã³ãŒããšããã®æ¬ã«ç€ºãããŠãããã¹ãŠã®ãã¹ãã®ãœãŒã¹ã³ãŒãã¯ã pragprog.comã«ããæ¬ã®WebããŒãžã®ãªã³ã¯ããå
¥æã§ããŸãã ãã¹ãã³ãŒããç解ããããã«ãœãŒã¹ã³ãŒããããŠã³ããŒãããå¿
èŠã¯ãããŸããã ãã¹ãã³ãŒãã¯ãäŸã§ã¯äŸ¿å©ãªåœ¢åŒã§ç€ºãããŠããŸãã ãã ãããããžã§ã¯ãã®ã¿ã¹ã¯ãå®è¡ãããããã¹ããµã³ãã«ã調æŽããŠèªåã®ãããžã§ã¯ãããã¹ããããããã«ã¯ïŒæãçžã£ãŠããªãïŒïŒãæžç±ã®WebããŒãžã«ã¢ã¯ã»ã¹ããŠäœåãããŠã³ããŒãããå¿
èŠããããŸãã æžç±ã®WebããŒãžã«ã¯ã æ£èª€è¡šã®ã¡ãã»ãŒãžãžã®ãªã³ã¯ãšãã£ã¹ã«ãã·ã§ã³ãã©ãŒã©ã ããããŸãã
ãã¿ãã¬ã®äžã«ã¯ããã®ã·ãªãŒãºã®èšäºã®ãªã¹ãããããŸãã
åã®ç« ã§ã¯ãpytestãå®è¡ããŸããã ãã¡ã€ã«ãšãã£ã¬ã¯ããªã䜿çšããŠå®è¡ããæ¹æ³ãšãæ©èœãããªãã·ã§ã³ã®æ°ã確èªããŸããã ãã®ç« ã§ã¯ãPythonããã±ãŒãžã®ãã¹ãã®ã³ã³ããã¹ãã§ãã¹ãé¢æ°ãäœæããæ¹æ³ãåŠç¿ããŸãã pytestã䜿çšããŠPythonããã±ãŒãžä»¥å€ã®ãã®ããã¹ãããå Žåããã®ç« ã®ã»ãšãã©ã圹ç«ã¡ãŸãã
Tasksããã±ãŒãžã®ãã¹ããäœæããŸãã ãããè¡ãåã«ãPythoné
åžããã±ãŒãžã®æ§é ãšãã®ãã¹ããããã³ãã¹ãã«ãã¹ãããã±ãŒãžã衚瀺ãããæ¹æ³ã«ã€ããŠèª¬æããŸãã 次ã«ããã¹ãã§ã¢ãµãŒãã䜿çšããæ¹æ³ããã¹ããäºæããªãäŸå€ãåŠçããæ¹æ³ãããã³äºæãããäŸå€ããã¹ãããæ¹æ³ã瀺ããŸãã
æåŸã«ãå€ãã®ãã¹ãããããŸãã ãã®æ¹æ³ã§ããã¹ããã¯ã©ã¹ãã¢ãžã¥ãŒã«ãããã³ãã£ã¬ã¯ããªã«æŽçããæ¹æ³ãåŠç¿ããŸãã 次ã«ãããŒã«ãŒã䜿çšããŠå®è¡ãããã¹ããããŒã¯ããæ¹æ³ã瀺ããçµã¿èŸŒã¿ããŒã«ãŒãã©ã®ããã«ãã¹ããã¹ãããããŠãã¹ããããŒã¯ãã倱æãæåŸ
ã§ãããã«ã€ããŠèª¬æããŸãã æåŸã«ããã¹ãã®ãã©ã¡ãŒã¿ãŒåã«ã€ããŠèª¬æããŸããããã«ãããç°ãªãããŒã¿ã§ãã¹ããåŒã³åºãããšãã§ããŸãã
ãã©ã³ã¹ã¬ãŒã¿ãŒæ³šïŒ Python 3.5ãŸãã¯3.6ã䜿çšããŠããå Žåã第2ç« ã®ãã¹ããå®è¡ãããšããã®ãããªã¡ãã»ãŒãžã衚瀺ãããå ŽåããããŸãã

ãã®åé¡ã¯ã ...\code\tasks_proj\src\tasks\tasksdb_tinydb.py
ããã¿ã¹ã¯ããã±ãŒãžãåã€ã³ã¹ããŒã«ããããšã§åŠçãããŸãã
$ cd /path/to/code $ pip install ./tasks_proj/`
ã¢ãžã¥ãŒã«ã®eids
doc_ids
ååä»ããã©ã¡ãŒã¿ãŒeid
ãšdoc_id
eid
ãdoc_ids
ããeids
ãŸã...\code\tasks_proj\src\tasks\tasksdb_tinydb.py
説æ#83783
åç
§ããŠãã ããã
ããã±ãŒãžãã¹ã
Pythonããã±ãŒãžã®ãã¹ãé¢æ°ã®äœææ¹æ³ãåŠç¿ããã«ã¯ãxiiããŒãžã®Tasksãããžã§ã¯ãã§èª¬æãããŠãããµã³ãã«Tasksãããžã§ã¯ãã䜿çšããŸãã ã¿ã¹ã¯ã¯ãåãã¿ã¹ã¯åã®ã³ãã³ãã©ã€ã³ããŒã«ãå«ãPythonããã±ãŒãžã§ãã
ä»é²4ãPythonãããžã§ã¯ãã®ããã±ãŒãžåãšé
åžïŒ175ããŒãžïŒã§ã¯ãå°èŠæš¡ãªããŒã å
ã§ããŒã«ã«ã«ããŸãã¯PyPIãä»ããŠã°ããŒãã«ã«ãããžã§ã¯ããé
åžããæ¹æ³ã«ã€ããŠèª¬æããŸãããã®ããã詳现ã«ã€ããŠã¯èª¬æããŸããã ãã ããTasksãããžã§ã¯ãã®å
容ãšããã®ãããžã§ã¯ãã®ãã¹ãå±¥æŽã«ããŸããŸãªãã¡ã€ã«ãã©ã®ããã«é©åããããç°¡åã«èŠãŠã¿ãŸãããã
Tasksãããžã§ã¯ãã®ãã¡ã€ã«æ§é ã¯æ¬¡ã®ãšããã§ãã
tasks_proj/ âââ CHANGELOG.rst âââ LICENSE âââ MANIFEST.in âââ README.rst âââ setup.py âââ src â âââ tasks â âââ __init__.py â âââ api.py â âââ cli.py â âââ config.py â âââ tasksdb_pymongo.py â âââ tasksdb_tinydb.py âââ tests âââ conftest.py âââ pytest.ini âââ func â âââ __init__.py â âââ test_add.py â âââ ... âââ unit âââ __init__.py âââ test_task.py âââ ...
ãããžã§ã¯ãã®å®å
šãªãªã¹ãïŒãã¹ããã¡ã€ã«ã®å®å
šãªãªã¹ããé€ãïŒãå«ããŠããã¹ãããããžã§ã¯ãã®ä»ã®éšåã«ã©ã®ããã«é©åãããã瀺ãããã¹ãã®éµãšãªãããã€ãã®ãã¡ã€ã«ãã€ãŸãconftest.pyãpytest.ini ãããŸããŸãª__init__.py
ãã¡ã€ã«ãšsetup.py
ãã¹ãŠã®ãã¹ãã¯ãã¹ãã«ä¿åããã srcã®ããã±ãŒãžãœãŒã¹ãã¡ã€ã«ãšã¯å¥ã«ä¿åãããŸãã ããã¯å®å
šãªèŠä»¶ã§ã¯ãããŸãããããã¹ããã©ã¯ãã£ã¹ã§ãã
CHANGELOG.rstãLICENSEãREADME.rstãMANIFEST.in ãããã³setup.pyã®ãã¹ãŠã®ãããã¬ãã«ãã¡ã€ã«ã«ã€ããŠã¯ãä»é²4 Pythonãããžã§ã¯ãã®ããã±ãŒãžåãšé
åžãããŒãž175ã§è©³ãã説æããŸããé
åžã®æ§ç¯ã«ã¯setup.pyãéèŠã§ãããããã±ãŒãžãããããã³ããã±ãŒãžãããŒã«ã«ã«ã€ã³ã¹ããŒã«ããŠãããã±ãŒãžãã€ã³ããŒãã§ããããã«ããããã
æ©èœãã¹ããšåäœãã¹ãã¯ãç¬èªã®ã«ã¿ãã°ã«åå²ãããŸãã ããã¯ä»»æã®æ±ºå®ã§ãããå¿
èŠã§ã¯ãããŸããã ãã ãããã¹ããã¡ã€ã«ãããã€ãã®ãã£ã¬ã¯ããªã«æŽçãããšããã¹ãã®ãµãã»ãããç°¡åã«å®è¡ã§ããŸãã æ©èœãã¹ãã¯ã·ã¹ãã ã®æ©èœãæå³çã«å€æŽããå Žåã«ã®ã¿æ©èœãããªãã¡ã¯ã¿ãªã³ã°ãå®è£
ã®å€æŽäžã«ãŠããããã¹ããæ©èœããªãå Žåããããããæ©èœãã¹ããšåäœãã¹ããåé¢ããã®ã奜ãã§ãã
ãããžã§ã¯ãã«ã¯2çš®é¡ã®__init__.py
ãã¡ã€ã«ãå«ãŸããŠããŸãïŒ src/
ãã£ã¬ã¯ããªã«ãããã¡ã€ã«ãštests/
ãã¡ã€ã«ã§ãã src/tasks/__init__.py
ã¯ããã£ã¬ã¯ããªãããã±ãŒãžã§ããããšãPythonã«äŒããŸãã ãŸãã誰ããimport tasks
䜿çšãããšãã«ãããã±ãŒãžã®ã¡ã€ã³ã€ã³ã¿ãŒãã§ã€ã¹ãšããŠæ©èœããŸãã api.py
ããç¹å®ã®é¢æ°ãã€ã³ããŒãããã³ãŒããå«ãŸããŠããããã cli.py
ãšãã¹ããã¡ã€ã«ã¯tasks.add()
ãå®è¡ãã代ããã«ã tasks.add()
ãªã©ã®ããã±ãŒãžé¢æ°ã«ã¢ã¯ã»ã¹ã§ããŸãã ãã¡ã€ã«tests/func/__init__.py
ããã³tests/unit/__init__.py
ã¯ç©ºã§ãã pytestã«1ã€ã®ãã£ã¬ã¯ããªã«ç§»åããŠããã¹ããã£ã¬ã¯ããªã®ã«ãŒããšpytest.ini
ãã¡ã€ã«ãèŠã€ããããã«pytest.ini
ãŸãã
pytest.ini
ãã¡ã€ã«ã¯ãªãã·ã§ã³ã§ãã ãããžã§ã¯ãå
šäœã®äžè¬çãªpytestæ§æãå«ãŸããŠããŸãã ããªãã®ãããžã§ã¯ãã¯ãããã®ãã¡ã®äžã€ä»¥äžãæããªãã¯ãã§ãã åžžã«äœ¿çšããããã©ã¡ãŒã¿ãŒã®ãªã¹ããèšå®ãããªã©ãpytestã®åäœãå€æŽãããã£ã¬ã¯ãã£ããå«ããããšãã§ããŸãã pytest.ini
ãã¹ãŠã«ã€ããŠã¯ã113ããŒãžã®ç¬¬6ç« ãæ§æãã§åŠç¿ããŸãã
conftest.pyãã¡ã€ã«ããªãã·ã§ã³ã§ãã pytestã¯ãããŒã«ã«ãã©ã°ã€ã³ããšèŠãªãããããã¯é¢æ°ãšãã£ã¯ã¹ãã£ãå«ãå ŽåããããŸãã ããã¯é¢æ°ã¯ãpytestã©ã³ã¿ã€ã ã®äžéšã«ã³ãŒãã貌ãä»ããŠãpytestã®åäœãå€æŽããæ¹æ³ã§ãã ãã£ã¯ã¹ãã£ã¯ããã¹ãé¢æ°ã®ååŸã«å®è¡ãããã»ããã¢ããããã³ãã£ã¢ããŠã³é¢æ°ã§ããããã¹ãã§äœ¿çšããããªãœãŒã¹ãšããŒã¿ãè¡šãããã«äœ¿çšã§ããŸãã ïŒãã£ã¯ã¹ãã£ã«ã€ããŠã¯ã第3ç« pytestãã£ã¯ã¹ãã£ïŒ49ããŒãžïŒããã³ç¬¬4ç« çµã¿èŸŒã¿ãã£ã¯ã¹ãã£ïŒ71ããŒãžïŒã§èª¬æããããã¯é¢æ°ã«ã€ããŠã¯ã第5ç« ããã©ã°ã€ã³ãïŒ95ããŒãžïŒã§èª¬æããŸããïŒã§äœ¿çšãããããã¯é¢æ°ããã³ãã£ã¯ã¹ãã£ããã€ãã®ãµããã£ã¬ã¯ããªã®ãã¹ãã¯ãtests / conftest.pyã«å«ãŸããŠããå¿
èŠããããŸãã conftest.pyãã¡ã€ã«ãããã€ãæã€ããšãã§ããŸãã ããšãã°ããã¹ãã«1ã€ãåãã¹ããµããã£ã¬ã¯ããªã«1ã€ãæã€ããšãã§ããŸãã
ãŸã è¡ã£ãŠããªãå Žåã¯ããã®ãããžã§ã¯ãã®ãœãŒã¹ã³ãŒãã®ã³ããŒãæ¬ã®Webãµã€ãããããŠã³ããŒãã§ããŸãã ãŸãã¯ãåæ§ã®æ§é ã§ãããžã§ã¯ãã«åãçµãããšãã§ããŸãã
test_task.pyã¯æ¬¡ã®ãšããã§ãã
ch2 / tasks_proj / tests / unit / test_task.py
"""Test the Task data type.""" # -*- coding: utf-8 -*- from tasks import Task def test_asdict(): """_asdict() .""" 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 () .""" 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 def test_defaults(): """ .""" t1 = Task() t2 = Task(None, None, False, None) assert t1 == t2 def test_member_access(): """ .field namedtuple.""" t = Task('buy milk', 'brian') assert t.summary == 'buy milk' assert t.owner == 'brian' assert (t.done, t.id) == (False, None)
test_task.pyãã¡ã€ã«ã«ã¯ã次ã®ã€ã³ããŒãã¹ããŒãã¡ã³ããå«ãŸããŠããŸãã
from tasks import Task
ãã¹ãã§ã¿ã¹ã¯ãã€ã³ããŒãããããã¿ã¹ã¯ããäœããã€ã³ããŒããããããæè¯ã®æ¹æ³ã¯ãpipã䜿çšããŠã¿ã¹ã¯ãããŒã«ã«ã«ã€ã³ã¹ããŒã«ããããšã§ãã ããã¯ãpipãçŽæ¥åŒã³åºãããã®setup.pyãã¡ã€ã«ãããããå¯èœã§ãã
pip install .
ãå®è¡ããŠã¿ã¹ã¯ãpip install .
ãŸãã¯pip install -e .
tasks_projãã£ã¬ã¯ããªããã ãŸãã¯ã1ã¬ãã«äžã®ãã£ã¬ã¯ããªããpip install -e tasks_proj
ãå®è¡ããå¥ã®ãªãã·ã§ã³ïŒ
$ cd /path/to/code $ pip install ./tasks_proj/ $ pip install --no-cache-dir ./tasks_proj/ Processing ./tasks_proj Collecting click (from tasks==0.1.0) Downloading click-6.7-py2.py3-none-any.whl (71kB) ... Collecting tinydb (from tasks==0.1.0) Downloading tinydb-3.4.0.tar.gz Collecting six (from tasks==0.1.0) Downloading six-1.10.0-py2.py3-none-any.whl Installing collected packages: click, tinydb, six, tasks Running setup.py install for tinydb ... done Running setup.py install for tasks ... done Successfully installed click-6.7 six-1.10.0 tasks-0.1.0 tinydb-3.4.0
ã¿ã¹ã¯ã®ãã¹ãã®ã¿ãå®è¡ããå Žåã¯ããã®ã³ãã³ãã§å®è¡ã§ããŸãã ã¿ã¹ã¯ã®ã€ã³ã¹ããŒã«äžã«ãœãŒã¹ã³ãŒããå€æŽã§ããããã«ããå Žåã¯ã-eãªãã·ã§ã³ïŒç·šéå¯èœãªãç·šéå¯èœãã®å ŽåïŒãæå®ããŠã€ã³ã¹ããŒã«ã䜿çšããå¿
èŠããããŸãã
$ pip install -e ./tasks_proj/ Obtaining file:///path/to/code/tasks_proj Requirement already satisfied: click in /path/to/venv/lib/python3.6/site-packages (from tasks==0.1.0) Requirement already satisfied: tinydb in /path/to/venv/lib/python3.6/site-packages (from tasks==0.1.0) Requirement already satisfied: six in /path/to/venv/lib/python3.6/site-packages (from tasks==0.1.0) Installing collected packages: tasks Found existing installation: tasks 0.1.0 Uninstalling tasks-0.1.0: Successfully uninstalled tasks-0.1.0 Running setup.py develop for tasks Successfully installed tasks
次ã«ããã¹ããå®è¡ããŠã¿ãŸãã
$ cd /path/to/code/ch2/tasks_proj/tests/unit $ pytest test_task.py ===================== test session starts ====================== collected 4 items test_task.py .... =================== 4 passed in 0.01 seconds ===================
ã€ã³ããŒããæ©èœããŸããïŒ ä»ã®ãã¹ãã§ã€ã³ããŒãã¿ã¹ã¯ãå®å
šã«äœ¿çšã§ããããã«ãªããŸããã ããã§ã¯ãããã€ãã®ãã¹ããæžããŸãããã
assertæã䜿çšãã
ãã¹ãé¢æ°ãèšè¿°ãããšããéåžžã®Pythonã¹ããŒãã¡ã³ãã®ã¢ãµãŒãã¯ããã¹ãã®å€±æãå ±åããããã®äž»èŠãªããŒã«ã§ãã pytestã§ã®ãã®åçŽãã¯çŽ æŽãããã§ãã ããããå€ãã®éçºè
ãä»ã®ãã¬ãŒã ã¯ãŒã¯ã®äžã§pytestã䜿çšããçç±ã§ãã
ä»ã®ãã¹ããã©ãããã©ãŒã ã䜿çšããå Žåã¯ãããããããŸããŸãªã¢ãµãŒããã«ããŒé¢æ°ãèŠãã§ãããã ããšãã°ã次ã¯ã¢ãµãŒãããã³ã¢ãµãŒããã«ããŒé¢æ°ã®ããã€ãã®åœ¢åŒã®ãªã¹ãã§ãã
pytestã§ã¯ãä»»æã®åŒã§assert <expression>ã䜿çšã§ããŸãã åŒãããŒã«ã«å€æããããšãã«Falseãšè©äŸ¡ãããå Žåããã¹ãã¯å€±æããŸãã
pytestã«ã¯ãassertã®åŒã³åºããã€ã³ã¿ãŒã»ããããã¹ããŒãã¡ã³ãã倱æããçç±ã®è©³çŽ°ãäŒããããšãã§ãããã®ã«çœ®ãæãããassert rewritingãšããé¢æ°ãå«ãŸããŠããŸãã ããã€ãã®ã¹ããŒãã¡ã³ããšã©ãŒãèŠããšããã®æžãæããã©ãã»ã©äŸ¿å©ããèŠãŠã¿ãŸãããã
ch2 / tasks_proj / tests / unit / test_task_fail.py
""" the Task type .""" from tasks import Task def test_task_equality(): """ .""" t1 = Task('sit there', 'brian') t2 = Task('do something', 'okken') assert t1 == t2 def test_dict_equality(): """ , dicts, .""" t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() assert t1_dict == t2_dict
ãããã®ãã¹ãã¯ãã¹ãŠå€±æããŸããããã¬ãŒã¹å
ã®æ
å ±ã¯èå³æ·±ããã®ã§ãã
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\unit>pytest test_task_fail.py ============================= test session starts ============================= collected 2 items test_task_fail.py FF ================================== FAILURES =================================== _____________________________ test_task_equality ______________________________ def test_task_equality(): """Different tasks should not be equal.""" t1 = Task('sit there', 'brian') t2 = Task('do something', 'okken') > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Use -v to get the full diff test_task_fail.py:9: AssertionError _____________________________ test_dict_equality ______________________________ def test_dict_equality(): """Different tasks compared as dicts should not be equal.""" t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() > assert t1_dict == t2_dict E AssertionError: assert OrderedDict([...('id', None)]) == OrderedDict([(...('id', None)]) E Omitting 3 identical items, use -vv to show E Differing items: E {'owner': 'okken'} != {'owner': 'okkem'} E Use -v to get the full diff test_task_fail.py:16: AssertionError ========================== 2 failed in 0.30 seconds ===========================
ããïŒ ããã¯å€ãã®æ
å ±ã§ãã 倱æãããã¹ãããšã«ã倱æã€ã³ãžã±ãŒã¿ã䜿çšããŠæ£ç¢ºãªãšã©ãŒæååã衚瀺ãããŸãã è¡Eã¯ãã¢ãµãŒãã®å€±æã«é¢ããè¿œå æ
å ±ã瀺ããäœãåé¡ã§ãã£ãããç解ããã®ã«åœ¹ç«ã¡ãŸãã
ç§ã¯æå³çã«test_task_equality()
ã«2ã€ã®äžäžèŽãå
¥ããŸããããåã®ã³ãŒãã§ã¯æåã®äžäžèŽã®ã¿ã衚瀺ãããŸããã ãšã©ãŒã¡ãã»ãŒãžã«-v
ããŠããããã«ã -v
ãã©ã°ã䜿çšããŠåè©Šè¡ããŠãã ããã
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\unit>pytest -v test_task_fail.py ============================= test session starts ============================= collected 2 items test_task_fail.py::test_task_equality FAILED test_task_fail.py::test_dict_equality FAILED ================================== FAILURES =================================== _____________________________ test_task_equality ______________________________ def test_task_equality(): """Different tasks should not be equal.""" t1 = Task('sit there', 'brian') t2 = Task('do something', 'okken') > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Full diff: E - Task(summary='sit there', owner='brian', done=False, id=None) E ? ^^^ ^^^ ^^^^ E + Task(summary='do something', owner='okken', done=False, id=None) E ? +++ ^^^ ^^^ ^^^^ test_task_fail.py:9: AssertionError _____________________________ test_dict_equality ______________________________ def test_dict_equality(): """Different tasks compared as dicts should not be equal.""" t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() > assert t1_dict == t2_dict E AssertionError: assert OrderedDict([...('id', None)]) == OrderedDict([(...('id', None)]) E Omitting 3 identical items, use -vv to show E Differing items: E {'owner': 'okken'} != {'owner': 'okkem'} E Full diff: E {'summary': 'make sandwich', E - 'owner': 'okken', E ? ^... E E ...Full output truncated (5 lines hidden), use '-vv' to show test_task_fail.py:16: AssertionError ========================== 2 failed in 0.28 seconds ===========================
ãŸããç§ã¯ããããããã¯ãŒã«ã ãšæãïŒ pytestã¯äž¡æ¹ã®éããèŠã€ããããšãã§ããã ãã§ãªãããããã®éããã©ãã«ããããæ£ç¢ºã«ç€ºããŸããã ãã®äŸã§ã¯ãç䟡ã¢ãµãŒãã®ã¿ã䜿çšããŠããŸãã pytest.orgã«ã¯ãé©ç°çãªãã¬ãŒã¹ãããã°æ
å ±ãå«ãã¢ãµãŒãã¹ããŒãã¡ã³ãã®ããªãšãŒã·ã§ã³ãå€æ°ãããŸãã
äºæ³ãããäŸå€
Tasks APIã®ããã€ãã®å Žæã§äŸå€ãçºçããå¯èœæ§ããããŸãã tasks / api.pyã«ããé¢æ°ãç°¡åã«èŠãŠã¿ãŸãããã
def add(task): # type: (Task) -\> int def get(task_id): # type: (int) -\> Task def list_tasks(owner=None): # type: (str|None) -\> list of Task def count(): # type: (None) -\> int def update(task_id, task): # type: (int, Task) -\> None def delete(task_id): # type: (int) -\> None def delete_all(): # type: () -\> None def unique_id(): # type: () -\> int def start_tasks_db(db_path, db_type): # type: (str, str) -\> None def stop_tasks_db(): # type: () -\> None
cli.pyã®CLIã³ãŒããšapi.pyã®APIã³ãŒãã®éã«ã¯ãAPIé¢æ°ã«æž¡ãããã¿ã€ãã«é¢ããåæããããŸãã APIåŒã³åºãã¯ãåãæ£ãããªãå Žåã«äŸå€ãçºçããããšãæåŸ
ããå Žæã§ãã ãããã®é¢æ°ãæ£ããåŒã³åºãããªãå Žåã«äŸå€ãã¹ããŒãããããã«ããã«ã¯ããã¹ãé¢æ°ã§ééã£ãåã䜿çšããŠãæå³çã«TypeErroräŸå€ãã¹ããŒããpytest.raisesïŒäºæ³ãããäŸå€ïŒã§äœ¿çšããŸãã
ch2 / tasks_proj / tests / func / test_api_exceptions.py
""" - API.""" import pytest import tasks def test_add_raises(): """add() param.""" with pytest.raises(TypeError): tasks.add(task='not a Task object')
test_add_raises()
ã§ã pytest.raises(TypeError)
ïŒæ¬¡ã®ã³ãŒããããã¯ã®ãã¹ãŠãTypeErroräŸå€ãã¹ããŒããå¿
èŠãããããšãã¹ããŒãã¡ã³ããå ±åããŸãã äŸå€ãçºçããªãå Žåããã¹ãã¯å€±æããŸãã ãã¹ãã§å¥ã®äŸå€ãçºçããå Žåã倱æããŸãã
test_add_raises()
ã§äŸå€ã®ã¿ã€ãããã§ãã¯ããŸããã é€å€ãªãã·ã§ã³ã確èªããããšãã§ããŸãã start_tasks_db(db_path, db_type)
å Žåstart_tasks_db(db_path, db_type)
ãæååã§ããã ãã§ãªããå®éã«ã¯ 'tiny'ãŸã㯠'mongo'ã§ããå¿
èŠããããŸãã excinfoãè¿œå ããããšã§ãäŸå€ã¡ãã»ãŒãžãæ£ããããšã確èªã§ããŸãã
ch2 / tasks_proj / tests / func / test_api_exceptions.py
def test_start_tasks_db_raises(): """, .""" with pytest.raises(ValueError) as excinfo: tasks.start_tasks_db('some/great/path', 'mysql') exception_msg = excinfo.value.args[0] assert exception_msg == "db_type must be a 'tiny' or 'mongo'"
ããã«ããããã®äŸå€ããã詳ãã調ã¹ãããšãã§ããŸãã asã®åŸã®å€æ°åïŒãã®å Žåã¯excinfoïŒã«ã¯äŸå€æ
å ±ãå
¥åãããExceptionInfoåã«ãªããŸãã
ãã®å Žåãæåã®ïŒãããŠå¯äžã®ïŒäŸå€ãã©ã¡ãŒã¿ãŒãæååãšäžèŽããããšã確èªããå¿
èŠããããŸãã
ãã¹ãæ©èœã®ããŒãã³ã°
pytestã¯ããã¹ãæ©èœã«ããŒã«ãŒãé
眮ããã¯ãŒã«ãªã¡ã«ããºã ãæäŸããŸãã ãã¹ãã«ã¯è€æ°ã®ããŒã«ãŒãå«ããããšãã§ããããŒã«ãŒã¯è€æ°ã®ãã¹ãã«å«ããããšãã§ããŸãã
ããŒã«ãŒã¯ãå®éã«åäœã確èªããåŸã«æå³ãæã¡ãŸãã ã·ã¹ãã ã«æ·±å»ãªã®ã£ããããããã©ãããç¥ãããã«ããã¹ãã®ãµãã»ãããç°¡åãªãç
ãã¹ãããšããŠå®è¡ããããšããŸãã æ
£äŸã«ãããSmokeãã¹ãã¯å
æ¬çã§å³å¯ãªãã¹ãã¹ã€ãŒãã§ã¯ãªããéžæãããµãã»ããã§ããããã°ããå®è¡ããŠãã·ã¹ãã ã®ãã¹ãŠã®éšåã®å¥å
šæ§ã®é©åãªå
šäœåãéçºè
ã«æäŸã§ããŸãã
ã¿ã¹ã¯ãããžã§ã¯ãã«ã¹ã¢ãŒã¯ãã¹ãã¹ã€ãŒããè¿œå ããã«ã¯ãäžéšã®ãã¹ãã«@mark.pytest.smoke
ãè¿œå ããå¿
èŠããããŸãã ããã€ãã®test_api_exceptions.py
ãã¹ãã«è¿œå ããŠã¿ãŸãããïŒ smokeããã³getããŒã«ãŒã¯pytestã«çµã¿èŸŒãŸããŠããªãããšã«æ³šæããŠãã ãããç§ã¯ããããæãã€ããã°ããã§ãïŒã
ch2 / tasks_proj / tests / func / test_api_exceptions.py
@pytest.mark.smoke def test_list_raises(): """list() param.""" with pytest.raises(TypeError): tasks.list_tasks(owner=123) @pytest.mark.get @pytest.mark.smoke def test_get_raises(): """get() param.""" with pytest.raises(TypeError): tasks.get(task_id='123')
-m marker_name
ããŒã¯ããããã¹ãã®ã¿ãå®è¡ããŸãããïŒ
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests>cd func (venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v -m "smoke" test_api_exceptions.py ============================= test session starts ============================= collected 7 items test_api_exceptions.py::test_list_raises PASSED test_api_exceptions.py::test_get_raises PASSED ============================= 5 tests deselected ============================== =================== 2 passed, 5 deselected in 0.18 seconds ==================== (venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func> (venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v -m "get" test_api_exceptions.py ============================= test session starts ============================= collected 7 items test_api_exceptions.py::test_get_raises PASSED ============================= 6 tests deselected ============================== =================== 1 passed, 6 deselected in 0.13 seconds ====================
-v
--verbose
ç瞮圢ã§ãããå®è¡äžã®ãã¹ãã®ååã確èªã§ããããšãå¿ããªãã§ãã ããã -m 'smoke'ã䜿çšãããšã@ pytest.mark.smokeãšããã©ãã«ã®äž¡æ¹ã®ãã¹ããå®è¡ãããŸãã
-m
'get'ã䜿çšãããšã @pytest.mark.get
ããŒã¯ããã1ã€ã®ãã¹ããå®è¡ãããŸãã ãšãŠãç°¡åã§ãã
ãã¹ãŠãå¥è·¡ãšå¥è·¡ã«ãªããŸãïŒ -m
åŸã®åŒã¯and
ã or
ã or
not
䜿çšnot
ãŠè€æ°ã®ããŒã«ãŒnot
çµåã§ããŸãã
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v -m "smoke and get" test_api_exceptions.py ============================= test session starts ============================= collected 7 items test_api_exceptions.py::test_get_raises PASSED ============================= 6 tests deselected ============================== =================== 1 passed, 6 deselected in 0.13 seconds ====================
ãã®ãã¹ãã¯smoke
ã§ã®ã¿è¡ããããŒã«ãŒãget
ã not
ã䜿çšã§ããŸãïŒ
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v -m "smoke and not get" test_api_exceptions.py ============================= test session starts ============================= collected 7 items test_api_exceptions.py::test_list_raises PASSED ============================= 6 tests deselected ============================== =================== 1 passed, 6 deselected in 0.13 seconds ====================
-m 'smoke and not get'
è¿œå ãããšã @pytest.mark.smoke
ãã©ã°ãä»ãããã @pytest.mark.smoke
ã§ã¯ãã©ã°ãä»ããããŠããªããã¹ããéžæãããŸããã
ç
ãã¹ãå¡ãã€ã¶ã
以åã®ãã¹ãã¯ããŸã åççãªäžé£ã®smoke test
ããã«ã¯èŠããŸããã å®éã«ã¯ããŒã¿ããŒã¹ã«è§Šãããã¿ã¹ã¯ãè¿œå ããŸããã§ããã ãã¡ããã smoke test
ã¯ãããè¡ãå¿
èŠããããŸãã
ã¿ã¹ã¯ã®è¿œå ãæ€èšããããã€ãã®ãã¹ããè¿œå ãããã®ãã¡ã®1ã€ãã¹ã¢ãŒã¯ãã¹ãã¹ã€ãŒãã®äžéšãšããŠäœ¿çšããŸãããã
ch2 / tasks_proj / tests / func / test_add.py
""" API tasks.add ().""" import pytest import tasks from tasks import Task def test_add_returns_valid_id(): """tasks.add(valid task) .""" # GIVEN an initialized tasks db # WHEN a new task is added # THEN returned task_id is of type int new_task = Task('do something') task_id = tasks.add(new_task) assert isinstance(task_id, int) @pytest.mark.smoke def test_added_task_has_id_set(): """, task_id tasks.add().""" # GIVEN an initialized tasks db # AND a new task is added new_task = Task('sit in chair', owner='me', done=True) task_id = tasks.add(new_task) # WHEN task is retrieved task_from_db = tasks.get(task_id) # THEN task_id matches id field assert task_from_db.id == task_id
ãããã®ãã¹ãã¯äž¡æ¹ãšããåæåãããã¿ã¹ã¯ããŒã¿ããŒã¹ã«é¢ããGIVENã³ã¡ã³ããæã£ãŠããŸããããã¹ãã«ã¯åæåãããããŒã¿ããŒã¹ã¯ãããŸããã ãã¹ãåã«ããŒã¿ããŒã¹ãåæåãããã¹ãåŸã«ã¯ãªãŒã³ã¢ããããããã«ãã£ã¯ã¹ãã£ãå®çŸ©ã§ããŸãã
ch2 / tasks_proj / tests / func / test_add.py
@pytest.fixture(autouse=True) def initialized_tasks_db(tmpdir): """Connect to db before testing, disconnect after.""" # Setup : start db tasks.start_tasks_db(str(tmpdir), 'tiny') yield # # Teardown : stop db tasks.stop_tasks_db()
ãã®äŸã§äœ¿çšããããã£ã¯ã¹ãã£tmpdirã¯ãçµã¿èŸŒã¿ã®ãã£ã¯ã¹ãã£ã§ãã ãã«ãã€ã³ãã£ã¯ã¹ãã£ã«ã€ããŠã¯ã第4ç« ããã«ãã€ã³ãã£ã¯ã¹ãã£ãïŒ71ããŒãžïŒã§ãã¹ãŠåŠç¿ããç¬èªã®ãã£ã¯ã¹ãã£ã®èšè¿°æ¹æ³ãšããã®åäœæ¹æ³ã«ã€ããŠã¯ãããã§äœ¿çšããautouseãã©ã¡ãŒã¿ãå«ãã第3ç« ãpytestãã£ã¯ã¹ãã£ãïŒ49ããŒãžïŒã§åŠç¿ããŸãã
ãã¹ãã§äœ¿çšãããèªå䜿çšã¯ããã®ãã¡ã€ã«ã®ãã¹ãŠã®ãã¹ãããã£ã¯ã¹ãã£ã䜿çšããããšã瀺ããŠããŸãã yield
åã®ã³ãŒãã¯ãåãã¹ãã®åã«å®è¡ãããŸãã yield
åŸã®ã³ãŒãã¯ãã¹ãåŸã«å®è¡ãããŸãã å¿
èŠã«å¿ããŠãyieldã¯ãã¹ãã«ããŒã¿ãè¿ãããšãã§ããŸãã ãã以éã®ç« ã§ã¯ãã¹ãŠãæ€èšããŸãããããã§ã¯ãã¹ãçšã«ããŒã¿ããŒã¹ãäœããã®åœ¢ã§æ§æããå¿
èŠããããŸãããã®ããããã®ããã€ã¹ãåŸ
ã€å¿
èŠã¯ãããŸããïŒãã¡ãããã£ã¯ã¹ãã£ã§ãïŒïŒã ïŒpytestã¯ãunittestãnoseã§äœ¿çšããããããªãæ§åŒã®ã»ããã¢ããããã³ãã£ã¢ããŠã³æ©èœããµããŒãããŠããŸãããããã»ã©èå³æ·±ããã®ã§ã¯ãããŸããããã ããèå³ãããå Žåã¯ãä»é²5ãxUnitãã£ã¯ã¹ãã£ã183ããŒãžã§èª¬æããŸããïŒ
ãšãããããã£ã¯ã¹ãã£ã®èª¬æã延æãããããžã§ã¯ãã®æåã«é²ã¿ã ã¹ã¢ãŒã¯ãã¹ãã¹ã€ãŒããå®è¡ããŸãããã
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>cd .. (venv33) ...\bopytest-code\code\ch2\tasks_proj\tests>cd .. (venv33) ...\bopytest-code\code\ch2\tasks_proj>pytest -v -m "smoke" ============================= test session starts ============================= collected 56 items tests/func/test_add.py::test_added_task_has_id_set PASSED tests/func/test_api_exceptions.py::test_list_raises PASSED tests/func/test_api_exceptions.py::test_get_raises PASSED ============================= 53 tests deselected ============================= =================== 3 passed, 53 deselected in 0.49 seconds ===================
, .
(Skipping Tests)
, , . 31 , pytest : skip
, skipif
, xfail
. skip
skipif
, -xfail
.
skip
skipif
, . , , , tasks.unique_id()
. ? , ?
-, (, initialized_tasks_db
; ):
ch2/tasks_proj/tests/func/ test_unique_id_1.py
"""Test tasks.unique_id().""" import pytest import tasks def test_unique_id(): """ unique_id () .""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest test_unique_id_1.py ============================= test session starts ============================= collected 1 item test_unique_id_1.py F ================================== FAILURES =================================== _______________________________ test_unique_id ________________________________ def test_unique_id(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() > assert id_1 != id_2 E assert 1 != 1 test_unique_id_1.py:11: AssertionError ========================== 1 failed in 0.30 seconds ===========================
ãã , . API , , docstring """Return an integer that does not exist in the db.""", , DB . . , :
ch2/tasks_proj/tests/func/ test_unique_id_2.py
@pytest.mark.skip(reason='misunderstood the API') def test_unique_id_1(): """ unique_id () .""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 def test_unique_id_2(): """unique_id() id.""" ids = [] ids.append(tasks.add(Task('one'))) ids.append(tasks.add(Task('two'))) ids.append(tasks.add(Task('three'))) # id uid = tasks.unique_id() # , assert uid not in ids
, , , @pytest..skip()
.
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_unique_id_2.py ============================= test session starts ============================= collected 2 items test_unique_id_2.py::test_unique_id_1 SKIPPED test_unique_id_2.py::test_unique_id_2 PASSED ===================== 1 passed, 1 skipped in 0.19 seconds =====================
, - , , 0.2.0 . skipif:
ch2/tasks_proj/tests/func/ test_unique_id_3.py
@pytest.mark.skipif(tasks.__version__ < '0.2.0', reason='not supported until version 0.2.0') def test_unique_id_1(): """ unique_id () .""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2
, skipif()
, Python. , , . skip , skipif . skip , skipif . ( reason ) skip , skipif xfail . :
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest test_unique_id_3.py ============================= test session starts ============================= collected 2 items test_unique_id_3.py s. ===================== 1 passed, 1 skipped in 0.20 seconds =====================
s.
, (skipped), (passed). , - -v
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_unique_id_3.py ============================= test session starts ============================= collected 2 items test_unique_id_3.py::test_unique_id_1 SKIPPED test_unique_id_3.py::test_unique_id_2 PASSED ===================== 1 passed, 1 skipped in 0.19 seconds =====================
. -rs
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -rs test_unique_id_3.py ============================= test session starts ============================= collected 2 items test_unique_id_3.py s. =========================== short test summary info =========================== SKIP [1] func\test_unique_id_3.py:8: not supported until version 0.2.0 ===================== 1 passed, 1 skipped in 0.22 seconds =====================
-r chars
:
$ pytest --help ... -r chars show extra test summary info as specified by chars ( , ) (f)ailed, (E)error, (s)skipped, (x)failed, (X)passed, (p)passed, (P)passed with output, (a)all except pP. ...
, .
skip
skipif
, . xfail
pytest , , . unique_id ()
, xfail
:
ch2/tasks_proj/tests/func/ test_unique_id_4.py
@pytest.mark.xfail(tasks.__version__ < '0.2.0', reason='not supported until version 0.2.0') def test_unique_id_1(): """ unique_id() .""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 @pytest.mark.xfail() def test_unique_id_is_a_duck(): """ xfail.""" uid = tasks.unique_id() assert uid == 'a duck' @pytest.mark.xfail() def test_unique_id_not_a_duck(): """ xpass.""" uid = tasks.unique_id() assert uid != 'a duck'
Running this shows:
, , xfail
. == vs.! =. .
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest test_unique_id_4.py ============================= test session starts ============================= collected 4 items test_unique_id_4.py xxX. =============== 1 passed, 2 xfailed, 1 xpassed in 0.36 seconds ================
X XFAIL, « ( expected to fail )». X XPASS «, , ( expected to fail but passed. )».
--verbose
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_unique_id_4.py ============================= test session starts ============================= collected 4 items test_unique_id_4.py::test_unique_id_1 xfail test_unique_id_4.py::test_unique_id_is_a_duck xfail test_unique_id_4.py::test_unique_id_not_a_duck XPASS test_unique_id_4.py::test_unique_id_2 PASSED =============== 1 passed, 2 xfailed, 1 xpassed in 0.36 seconds ================
pytest , , , xfail
, FAIL. pytest.ini :
[pytest] xfail_strict=true
pytest.ini 6, , . 113.
, ââ . . , , . , . . .
A Single Directory
, pytest :
(venv33) ...\bopytest-code\code\ch2\tasks_proj>pytest tests\func --tb=no ============================= test session starts ============================= collected 50 items tests\func\test_add.py .. tests\func\test_add_variety.py ................................ tests\func\test_api_exceptions.py ....... tests\func\test_unique_id_1.py F tests\func\test_unique_id_2.py s. tests\func\test_unique_id_3.py s. tests\func\test_unique_id_4.py xxX. ==== 1 failed, 44 passed, 2 skipped, 2 xfailed, 1 xpassed in 1.75 seconds =====
, -v
, .
(venv33) ...\bopytest-code\code\ch2\tasks_proj>pytest -v tests\func --tb=no ============================= test session starts =============================
...
collected 50 items tests\func\test_add.py::test_add_returns_valid_id PASSED tests\func\test_add.py::test_added_task_has_id_set PASSED tests\func\test_add_variety.py::test_add_1 PASSED tests\func\test_add_variety.py::test_add_2[task0] PASSED tests\func\test_add_variety.py::test_add_2[task1] PASSED tests\func\test_add_variety.py::test_add_2[task2] PASSED tests\func\test_add_variety.py::test_add_2[task3] PASSED tests\func\test_add_variety.py::test_add_3[sleep-None-False] PASSED ... tests\func\test_unique_id_2.py::test_unique_id_1 SKIPPED tests\func\test_unique_id_2.py::test_unique_id_2 PASSED ... tests\func\test_unique_id_4.py::test_unique_id_1 xfail tests\func\test_unique_id_4.py::test_unique_id_is_a_duck xfail tests\func\test_unique_id_4.py::test_unique_id_not_a_duck XPASS tests\func\test_unique_id_4.py::test_unique_id_2 PASSED ==== 1 failed, 44 passed, 2 skipped, 2 xfailed, 1 xpassed in 2.05 seconds =====
, .
File/Module
, , pytest:
$ cd /path/to/code/ch2/tasks_proj $ pytest tests/func/test_add.py =========================== test session starts =========================== collected 2 items tests/func/test_add.py .. ======================== 2 passed in 0.05 seconds =========================
.
, ::
:
$ cd /path/to/code/ch2/tasks_proj $ pytest -v tests/func/test_add.py::test_add_returns_valid_id =========================== test session starts =========================== collected 3 items tests/func/test_add.py::test_add_returns_valid_id PASSED ======================== 1 passed in 0.02 seconds =========================
-v
, , .
Test Class
Here's an example:
â , .
以äžã«äŸã瀺ããŸãã
ch2/tasks_proj/tests/func/ test_api_exceptions.py
class TestUpdate(): """ tasks.update().""" def test_bad_id(self): """non-int id excption.""" with pytest.raises(TypeError): tasks.update(task_id={'dict instead': 1}, task=tasks.Task()) def test_bad_task(self): """A non-Task task excption.""" with pytest.raises(TypeError): tasks.update(task_id=1, task='not a task')
, update()
, . , , ::
, :
(venv33) ...\bopytest-code\code\ch2\tasks_proj>pytest -v tests/func/test_api_exceptions.py::TestUpdate ============================= test session starts ============================= collected 2 items tests\func\test_api_exceptions.py::TestUpdate::test_bad_id PASSED tests\func\test_api_exceptions.py::TestUpdate::test_bad_task PASSED ========================== 2 passed in 0.12 seconds ===========================
A Single Test Method of a Test Class
, â ::
:
$ cd /path/to/code/ch2/tasks_proj $ pytest -v tests/func/test_api_exceptions.py::TestUpdate::test_bad_id ===================== test session starts ====================== collected 1 item tests/func/test_api_exceptions.py::TestUpdate::test_bad_id PASSED =================== 1 passed in 0.03 seconds ===================
,
, , , , . , pytest -v
.
-k
, . and
, or
not
. , _raises
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj>pytest -v -k _raises ============================= test session starts ============================= collected 56 items tests/func/test_api_exceptions.py::test_add_raises PASSED tests/func/test_api_exceptions.py::test_list_raises PASSED tests/func/test_api_exceptions.py::test_get_raises PASSED tests/func/test_api_exceptions.py::test_delete_raises PASSED tests/func/test_api_exceptions.py::test_start_tasks_db_raises PASSED ============================= 51 tests deselected ============================= =================== 5 passed, 51 deselected in 0.54 seconds ===================
and
not
test_delete_raises()
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj>pytest -v -k "_raises and not delete" ============================= test session starts ============================= collected 56 items tests/func/test_api_exceptions.py::test_add_raises PASSED tests/func/test_api_exceptions.py::test_list_raises PASSED tests/func/test_api_exceptions.py::test_get_raises PASSED tests/func/test_api_exceptions.py::test_start_tasks_db_raises PASSED ============================= 52 tests deselected ============================= =================== 4 passed, 52 deselected in 0.44 seconds ===================
, , , -k
. , , .
[Parametrized Testing]:
, , . . - pytest, - .
, , add()
:
ch2/tasks_proj/tests/func/ test_add_variety.py
""" API tasks.add().""" import pytest import tasks from tasks import Task def test_add_1(): """tasks.get () id, add() works.""" task = Task('breathe', 'BRIAN', True) task_id = tasks.add(task) t_from_db = tasks.get(task_id) # , , assert equivalent(t_from_db, task) def equivalent(t1, t2): """ .""" # , id return ((t1.summary == t2.summary) and (t1.owner == t2.owner) and (t1.done == t2.done)) @pytest.fixture(autouse=True) def initialized_tasks_db(tmpdir): """ , .""" tasks.start_tasks_db(str(tmpdir), 'tiny') yield tasks.stop_tasks_db()
tasks id
None
. id
. ==
, , . equivalent()
, id
. autouse
, , . , :
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_add_variety.py::test_add_1 ============================= test session starts ============================= collected 1 item test_add_variety.py::test_add_1 PASSED ========================== 1 passed in 0.69 seconds ===========================
. , . , ? . @pytest.mark.parametrize(argnames, argvalues)
, :
ch2/tasks_proj/tests/func/ test_add_variety.py
@pytest.mark.parametrize('task', [Task('sleep', done=True), Task('wake', 'brian'), Task('breathe', 'BRIAN', True), Task('exercise', 'BrIaN', False)]) def test_add_2(task): """ .""" task_id = tasks.add(task) t_from_db = tasks.get(task_id) assert equivalent(t_from_db, task)
parametrize()
â â 'task', . â , Task. pytest :
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_add_variety.py::test_add_2 ============================= test session starts ============================= collected 4 items test_add_variety.py::test_add_2[task0] PASSED test_add_variety.py::test_add_2[task1] PASSED test_add_variety.py::test_add_2[task2] PASSED test_add_variety.py::test_add_2[task3] PASSED ========================== 4 passed in 0.69 seconds ===========================
parametrize()
. , , :
ch2/tasks_proj/tests/func/ test_add_variety.py
@pytest.mark.parametrize('summary, owner, done', [('sleep', None, False), ('wake', 'brian', False), ('breathe', 'BRIAN', True), ('eat eggs', 'BrIaN', False), ]) def test_add_3(summary, owner, done): """ .""" task = Task(summary, owner, done) task_id = tasks.add(task) t_from_db = tasks.get(task_id) assert equivalent(t_from_db, task)
, pytest, , :
(venv35) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_add_variety.py::test_add_3 ============================= test session starts ============================= platform win32 -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- cachedir: ..\.pytest_cache rootdir: ...\bopytest-code\code\ch2\tasks_proj\tests, inifile: pytest.ini collected 4 items test_add_variety.py::test_add_3[sleep-None-False] PASSED [ 25%] test_add_variety.py::test_add_3[wake-brian-False] PASSED [ 50%] test_add_variety.py::test_add_3[breathe-BRIAN-True] PASSED [ 75%] test_add_variety.py::test_add_3[eat eggs-BrIaN-False] PASSED [100%] ========================== 4 passed in 0.37 seconds ===========================
, , pytest, :
(venv35) c:\BOOK\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_add_variety.py::test_add_3[sleep-None-False] ============================= test session starts ============================= test_add_variety.py::test_add_3[sleep-None-False] PASSED [100%] ========================== 1 passed in 0.22 seconds ===========================
, :
(venv35) c:\BOOK\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v "test_add_variety.py::test_add_3[eat eggs-BrIaN-False]" ============================= test session starts ============================= collected 1 item test_add_variety.py::test_add_3[eat eggs-BrIaN-False] PASSED [100%] ========================== 1 passed in 0.56 seconds ===========================
, :
ch2/tasks_proj/tests/func/ test_add_variety.py
tasks_to_try = (Task('sleep', done=True), Task('wake', 'brian'), Task('wake', 'brian'), Task('breathe', 'BRIAN', True), Task('exercise', 'BrIaN', False)) @pytest.mark.parametrize('task', tasks_to_try) def test_add_4(task): """ .""" task_id = tasks.add(task) t_from_db = tasks.get(task_id) assert equivalent(t_from_db, task)
. :
(venv35) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_add_variety.py::test_add_4 ============================= test session starts ============================= collected 5 items test_add_variety.py::test_add_4[task0] PASSED [ 20%] test_add_variety.py::test_add_4[task1] PASSED [ 40%] test_add_variety.py::test_add_4[task2] PASSED [ 60%] test_add_variety.py::test_add_4[task3] PASSED [ 80%] test_add_variety.py::test_add_4[task4] PASSED [100%] ========================== 5 passed in 0.34 seconds ===========================
, . , ids parametrize()
, . ids
, . , tasks_to_try
, :
ch2/tasks_proj/tests/func/ test_add_variety.py
task_ids = ['Task({},{},{})'.format(t.summary, t.owner, t.done) for t in tasks_to_try] @pytest.mark.parametrize('task', tasks_to_try, ids=task_ids) def test_add_5(task): """Demonstrate ids.""" task_id = tasks.add(task) t_from_db = tasks.get(task_id) assert equivalent(t_from_db, task)
, :
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_add_variety.py::test_add_5 ============================= test session starts ============================= collected 5 items test_add_variety.py::test_add_5[Task(sleep,None,True)] PASSED test_add_variety.py::test_add_5[Task(wake,brian,False)0] PASSED test_add_variety.py::test_add_5[Task(wake,brian,False)1] PASSED test_add_variety.py::test_add_5[Task(breathe,BRIAN,True)] PASSED test_add_variety.py::test_add_5[Task(exercise,BrIaN,False)] PASSED ========================== 5 passed in 0.45 seconds ===========================
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v "test_add_variety.py::test_add_5[Task(exercise,BrIaN,False)]" ============================= test session starts ============================= collected 1 item test_add_variety.py::test_add_5[Task(exercise,BrIaN,False)] PASSED ========================== 1 passed in 0.21 seconds ===========================
; shell. parametrize()
. :
ch2/tasks_proj/tests/func/ test_add_variety.py
@pytest.mark.parametrize('task', tasks_to_try, ids=task_ids) class TestAdd(): """ .""" def test_equivalent(self, task): """ , .""" task_id = tasks.add(task) t_from_db = tasks.get(task_id) assert equivalent(t_from_db, task) def test_valid_id(self, task): """ .""" task_id = tasks.add(task) t_from_db = tasks.get(task_id) assert t_from_db.id == task_id
:
(venv33) ...\bopytest-code\code\ch2\tasks_proj\tests\func>pytest -v test_add_variety.py::TestAdd ============================= test session starts ============================= collected 10 items test_add_variety.py::TestAdd::test_equivalent[Task(sleep,None,True)] PASSED test_add_variety.py::TestAdd::test_equivalent[Task(wake,brian,False)0] PASSED test_add_variety.py::TestAdd::test_equivalent[Task(wake,brian,False)1] PASSED test_add_variety.py::TestAdd::test_equivalent[Task(breathe,BRIAN,True)] PASSED test_add_variety.py::TestAdd::test_equivalent[Task(exercise,BrIaN,False)] PASSED test_add_variety.py::TestAdd::test_valid_id[Task(sleep,None,True)] PASSED test_add_variety.py::TestAdd::test_valid_id[Task(wake,brian,False)0] PASSED test_add_variety.py::TestAdd::test_valid_id[Task(wake,brian,False)1] PASSED test_add_variety.py::TestAdd::test_valid_id[Task(breathe,BRIAN,True)] PASSED test_add_variety.py::TestAdd::test_valid_id[Task(exercise,BrIaN,False)] PASSED ========================== 10 passed in 1.16 seconds ==========================
, @pytest.mark.parametrize()
. pytest.param(<value\>, id="something")
:
:
(venv35) ...\bopytest-code\code\ch2\tasks_proj\tests\func $ pytest -v test_add_variety.py::test_add_6 ======================================== test session starts ========================================= collected 3 items test_add_variety.py::test_add_6[just summary] PASSED [ 33%] test_add_variety.py::test_add_6[summary\owner] PASSED [ 66%] test_add_variety.py::test_add_6[summary\owner\done] PASSED [100%] ================================ 3 passed, 6 warnings in 0.35 seconds ================================
, id
.
- ,
task_proj
, - , pip install /path/to/tasks_proj
. - .
- pytest .
- pytest ,
tasks_proj/tests/func
. pytest , . . , ? - xfail , pytest tests .
tasks.count()
, . API , , , .- ?
test_api_exceptions.py
. , . ( api.py
.)
次ã¯äœã§ãã
pytest . , , , . initialized_tasks_db
. / .
ãŸããè€æ°ã®ãã¹ãæ©èœãåãèšå®ã䜿çšã§ããããã«ãå
±éã³ãŒããåé¢ããããšãã§ããŸãã次ã®ç« ã§ã¯ããã£ã¯ã¹ãã£pytestã®çŽ æŽãããäžçã«æ·±ãå
¥ã蟌ã¿ãŸãã
æ»ã 次㞠