 æ»ã 次ãž
 æ»ã 次㞠
ããã«äœ¿ãã匷åãªpytestã¯ããã©ã°ã€ã³ã®ããã¯ã¹ã远å ãããšããã«è¯ããªããŸãã pytestã³ãŒãããŒã¹ã¯èšå®ãšæ¡åŒµæ©èœã§æ§æãããŠããããã©ã°ã€ã³ãä»ããŠå€æŽããã³æ¹åã§ããããã¯ããããŸãã

ãã®æ¬ã®äŸã¯ãPython 3.6ãšpytest 3.2ã䜿çšããŠæžãããŠããŸãã pytest 3.2ã¯ãPython 2.6ã2.7ãããã³Python 3.3+ããµããŒãããŠããŸãã
Tasksãããžã§ã¯ãã®ãœãŒã¹ã³ãŒããšããã®æ¬ã«ç€ºãããŠãããã¹ãŠã®ãã¹ãã®ãœãŒã¹ã³ãŒãã¯ã pragprog.comã«ããæ¬ã®WebããŒãžã®ãªã³ã¯ããå
¥æã§ããŸãã ãã¹ãã³ãŒããçè§£ããããã«ãœãŒã¹ã³ãŒããããŠã³ããŒãããå¿
èŠã¯ãããŸããã ãã¹ãã³ãŒãã¯ãäŸã§ã¯äŸ¿å©ãªåœ¢åŒã§ç€ºãããŠããŸãã ãã ãããããžã§ã¯ãã®ã¿ã¹ã¯ãå®è¡ãããããã¹ããµã³ãã«ã調æŽããŠèªåã®ãããžã§ã¯ãããã¹ããããããã«ã¯ïŒæãçžã£ãŠããªãïŒïŒãæžç±ã®WebããŒãžã«ã¢ã¯ã»ã¹ããŠäœåãããŠã³ããŒãããå¿
èŠããããŸãã æžç±ã®WebããŒãžã«ã¯ã æ£èª€è¡šã®ã¡ãã»ãŒãžãžã®ãªã³ã¯ãšãã£ã¹ã«ãã·ã§ã³ãã©ãŒã©ã ããããŸãã
ãã¿ãã¬ã®äžã«ã¯ããã®ã·ãªãŒãºã®èšäºã®ãªã¹ãããããŸãã
ããã«é²ããŸãããïŒ
ãã®æ¬ã®åã®ç« ã§äœæ¥ããå Žåããã§ã«ããã€ãã®ãã©ã°ã€ã³ãäœæããŠããããšã«é©ããããããŸããã ãããžã§ã¯ãã®ãããã¬ãã«ã®conftest.pyãã¡ã€ã«ã«ãã£ã¯ã¹ãã£ãããã¯é¢æ°ãé
眮ããconftest.py ãããŒã«ã«ã®conftestãã©ã°ã€ã³ãäœæããŸãã ãããã®conftest.pyãã¡ã€ã«ãããããžã§ã¯ãéãä»ã®äººããŸãã¯äžçãšå
±æã§ããã€ã³ã¹ããŒã«å¯èœãªãã©ã°ã€ã³ã«å€æããã®ã¯ã»ãã®å°ãã®è¿œå äœæ¥ã§ãã
ãã®ç« ã¯ããµãŒãããŒãã£ã®ãã©ã°ã€ã³ãæ¢ãå Žæã®è³ªåã«çããããšããå§ããŸãã ããªãã®æ°ã®ãã©ã°ã€ã³ãå©çšå¯èœã§ããããã誰ããpytestè¡ããã倿Žããã§ã«æžããŠããå¯èœæ§ãããªããããŸãã ç§ãã¡ã¯ãªãŒãã³ãœãŒã¹ã®ãã©ã°ã€ã³ãæ€èšããã®ã§ããã©ã°ã€ã³ãã»ãŒããªããããããããšãããŠããããããã§ãªãå Žåã¯ããã©ã°ã€ã³ãéçºããããåç
§ãšããŠäœ¿çšããŠç¬èªã®ãã©ã°ã€ã³ãäœæã§ããŸãã ãã®ç« ã¯ç¬èªã®ãã©ã°ã€ã³ã®äœæã«é¢ãããã®ã§ãããä»é²3ã Sampler Packãã©ã°ã€ã³ïŒ163ããŒãžïŒãå«ãŸããŠãããå¯èœãªããšã®æŠèŠã説æããŠããŸãã
ãã®ç« ã§ã¯ããã©ã°ã€ã³ã®äœææ¹æ³ãåŠã³ããã¹ããããã±ãŒãžã³ã°ãé
åžã®æ£ããæ¹åã瀺ããŸãã Pythonã®ããã±ãŒãžãšé
åžã«é¢ããå®å
šãªãããã¯ã¯åºç¯ã§ãããç¬èªã®æ¬ã§ãããšäž»åŒµããŠããããããã¹ãŠãç¶²çŸ
ããããã§ã¯ãããŸããã ããããããªãã¯ããªãã®ããŒã ãšãã©ã°ã€ã³ã亀æããããšãã§ããã®ã«ååãªæ
å ±ãåŸãŸãã ãŸããPyPIãµããŒããšæå°éã®äœæ¥ã§ãã©ã°ã€ã³ãäœæããããã€ãã®ç°¡åãªæ¹æ³ã«ã€ããŠã説æããŸãã
æ€çŽ¢ãã©ã°ã€ã³
ãµãŒãããŒãã£ã®pytestãã©ã°ã€ã³ã¯ããã€ãã®å Žæã«ãããŸãã ä»é²3ããã©ã°ã€ã³ãµã³ãã©ããã¯ïŒ163ããŒãžïŒã«ãªã¹ããããŠãããã©ââã°ã€ã³ã¯ãPyPIããããŠã³ããŒãã§ããŸãã ãã ããããã玠æŽãããpytestãã©ã°ã€ã³ãèŠã€ããå¯äžã®å Žæã§ã¯ãããŸããã
https://docs.pytest.org/en/latest/plugins.html
ã¡ã€ã³ã®pytestããã¥ã¡ã³ããµã€ãã«ã¯ãpytestãã©ã°ã€ã³ã®ã€ã³ã¹ããŒã«ãšäœ¿çšã«ã€ããŠèª¬æããããã€ãã®äžè¬çãªãã©ã°ã€ã³ããªã¹ãããããŒãžããããŸãã
https://pypi.python.org
Python Package IndexïŒPyPIïŒã¯ãå€ãã®Pythonããã±ãŒãžãå
¥æããã®ã«æé©ãªå Žæã§ãããpytestãã©ã°ã€ã³ãæ€çŽ¢ããã®ã«ãæé©ã§ãã ã»ãšãã©ã®pytestãã©ã°ã€ã³ã¯ãpytest-ãã§å§ãŸããã-pytestãã§çµãããããpytestãã©ã°ã€ã³ãæ€çŽ¢ãããšãã¯ãæ€çŽ¢ãã£ãŒã«ãã«ãpytestãããpytest-ããŸãã¯ã-pytestããšå
¥åããŸãã
https://github.com/pytest-dev
GitHubã®pytest-devã°ã«ãŒãã«ã¯ãpytestã®ãœãŒã¹ã³ãŒããä¿åãããŠããŸãã ããã«ãããã§ã¯ãpytestã«ãŒãã«ããŒã ãé·æçã«ãµããŒãããå¿
èŠããã人æ°ã®ããpytestãã©ã°ã€ã³ãèŠã€ããããšãã§ããŸãã
ãã©ã°ã€ã³ã®ã€ã³ã¹ããŒã«
Pytestãã©ã°ã€ã³ã¯ãä»ã®Pythonããã±ãŒãžãšåæ§ã«ãpipãšãšãã«ã€ã³ã¹ããŒã«ãããŸãã ããã
ãã©ã°ã€ã³ãã€ã³ã¹ããŒã«ããã«ã¯ãããã€ãã®æ¹æ³ã§pipã䜿çšã§ããŸãã
PyPIããã€ã³ã¹ããŒã«ãã
PyPIã¯pipã®ããã©ã«ãã®å Žæã§ãããããPyPIãããã©ã°ã€ã³ãã€ã³ã¹ããŒã«ããã®ãæãç°¡åãªæ¹æ³ã§ãã pytest-covãã©ã°ã€ã³ãã€ã³ã¹ããŒã«ããŸãããã
 $ pip install pytest-cov 
PyPIã®ææ°ã®å®å®ããŒãžã§ã³ãã€ã³ã¹ããŒã«ãããŸãã
PyPIããç¹å®ã®ããŒãžã§ã³ãã€ã³ã¹ããŒã«ãã
ãã©ã°ã€ã³ã®ç¹å®ã®ããŒãžã§ã³ãå¿
èŠãªå Žåã¯ã ==åŸã«ããŒãžã§ã³ãæå®ã§ããŸãã
 $ pip install pytest-cov==2.4.0 
.tar.gzãŸãã¯.whlãã¡ã€ã«ããã€ã³ã¹ããŒã«ãã
PyPIããã±ãŒãžã¯ãæ¡åŒµåã.tar.gzãŸãã¯.whl zipãã¡ã€ã«ãšããŠé
åžãããŸãã 圌ãã¯ãã°ãã°ãã¿ãŒã«ããŒã«ããšããã€ãŒã«ããšåŒã°ããŸãã PyPIãçŽæ¥æäœããããšãããšåé¡ãçºçããå ŽåïŒãã¡ã€ã¢ãŠã©ãŒã«ããã®ä»ã®ãããã¯ãŒã¯ã®è€éãª.whlã§çºçããå¯èœæ§ããããŸãïŒ .whlãŸãã¯.whlãããŠã³ããŒãããŠã .whlããã€ã³ã¹ããŒã«ã§ããŸãã
ã¿ã³ããªã³ã§é梱ããããã³ã¹ãããããå¿
èŠã¯ãããŸããã ããããåããã ãã§ãïŒ
 $ pip install pytest-cov-2.4.0.tar.gz # or $ pip install pytest_cov-2.4.0-py2.py3-none-any.whl 
ããŒã«ã«ãã£ã¬ã¯ããªããã®ã€ã³ã¹ããŒã«
.tar.gzãŸãã¯.whlããŒã«ã«ãŸãã¯å
±æãã£ã¬ã¯ããªã«ãã©ã°ã€ã³ïŒããã³ä»ã®Pythonããã±ãŒãžïŒçšã®ãã©ã°ã€ã³ãçšæããPyPIã®ä»£ããã«ããã䜿çšããŠãã©ã°ã€ã³ãã€ã³ã¹ããŒã«ã§ããŸãã
 $ mkdir some_plugins $ cp pytest_cov-2.4.0-py2.py3-none-any.whl some_plugins/ $ pip install --no-index --find-links=./some_plugins/ pytest-cov 
--no-indexã¯ãPipã«PyPIã«æ¥ç¶ããªãããã«æç€ºããŸãã --find-links=./some_plugins/ã¯ãpipã«some_pluginsãã£ã¬ã¯ããªã調ã¹ãããã«æç€ºããŸãã ãã®æ¹æ³ã¯ããµãŒãããŒãã£ãšãã€ãã£ãã®äž¡æ¹ã®ãã©ã°ã€ã³ãããŒã«ã«ã«ä¿åãããŠããå Žåãããã³ç¶ç¶ççµ±åãŸãã¯toxã䜿çšããŠæ°ããä»®æ³ç°å¢ãäœæããŠããå Žåã«ç¹ã«äŸ¿å©ã§ãã ïŒToxãšç¶ç¶çã€ã³ãã°ã¬ãŒã·ã§ã³ã®äž¡æ¹ã«ã€ããŠã¯ã第7ç« ã§pytestãä»ã®ããŒã«ãšäœ¿çšããŠã125ããŒãžã§èª¬æããŸããïŒ
ããŒã«ã«ãã£ã¬ã¯ããªã®ã€ã³ã¹ããŒã«æ¹æ³ã䜿çšãããšã==ãšããŒãžã§ã³çªå·ã远å ããŠãè€æ°ã®ããŒãžã§ã³ãã€ã³ã¹ããŒã«ããå¿
èŠãªããŒãžã§ã³ãæå®ã§ããããšã«æ³šæããŠãã ããã
 $ pip install --no-index --find-links=./some_plugins/ pytest-cov==2.4.0 
Gitãªããžããªããã€ã³ã¹ããŒã«ãã
ãã®å Žåã¯GitHubã®Gitãªããžããªãããã©ã°ã€ã³ãçŽæ¥ã€ã³ã¹ããŒã«ã§ããŸãã
 $ pip install git+https://github.com/pytest-dev/pytest-cov 
ããŒãžã§ã³ã¿ã°ãæå®ããããšãã§ããŸãã
 $ pip install git+https://github.com/pytest-dev/pytest-cov@v2.4.0 
ãŸãã¯ããã©ã³ããæå®ã§ããŸãïŒ
 $ pip install git+https://github.com/pytest-dev/pytest-cov@master 
Gitãªããžããªããã®ã€ã³ã¹ããŒã«ã¯ãGitã«ç¬èªã®äœæ¥ãä¿åããŠããå ŽåããŸãã¯ãã©ã°ã€ã³ãŸãã¯ãã©ã°ã€ã³ã®å¿
èŠãªããŒãžã§ã³ãPyPIã«ãªãå Žåã«ç¹ã«äŸ¿å©ã§ãã
翻蚳è
泚ïŒ
pipã¯GitãMercurialãSubversionãããã³Bazaarããã®ã€ã³ã¹ããŒã«ããµããŒãããURLãã¬ãã£ãã¯ã¹ã䜿çšããŠVCSã¿ã€ããå®çŸ©ããŸãïŒãgit +ãããhg +ãããsvn +ãããbzr +ãã
詳现ã«ã€ããŠã¯ã PyPIã®ããã¥ã¡ã³ããåç
§ããŠãã ããã
ç¬èªã®ãã©ã°ã€ã³ãæžã
å€ãã®ãµãŒãããŒãã£ãã©ã°ã€ã³ã«ã¯ãéåžžã«å€ãã®ã³ãŒããå«ãŸããŠããŸãã ããã¯ãããããã¹ãŠãèªåã§éçºããæéãç¯çŽããããã«äœ¿çšããçç±ã®1ã€ã§ãã ãã ããç¹å®ã®ã³ãŒãã«ã€ããŠã¯ããã¹ãã«åœ¹ç«ã€ç¹å¥ãªãã£ã¯ã¹ãã£ãšä¿®æ£ãééããªãæãä»ããŸãã ãã©ã°ã€ã³ãäœæããããšã«ãããè€æ°ã®ãããžã§ã¯ãéã§å
±æãããè€æ°ã®ãã£ã¯ã¹ãã£ãç°¡åã«å
±æã§ããŸãã ç¬èªã®ãã©ã°ã€ã³ãéçºããã³é
åžããããšã«ããããããã®å€æŽãããã€ãã®ãããžã§ã¯ãïŒå Žåã«ãã£ãŠã¯ä»ã®å°åïŒãšå
±æã§ããŸãã ããã¯éåžžã«ç°¡åã§ãã ãã®ã»ã¯ã·ã§ã³ã§ã¯ãpytestã®åäœã®å°ããªå€æŽãéçºãããã©ã°ã€ã³ãšããŠããã¯ãããã¹ãããŠãé
åžæ¹æ³ãæ€èšããŸãã
ãã©ã°ã€ã³ã«ã¯ãpytestã®åäœã倿Žããããã¯é¢æ°ãå«ããããšãã§ããŸãã pytestã¯ãã©ã°ã€ã³ãpytestã®åäœããããã«å€æŽã§ããããã«èšèšãããŠãããããå€ãã®ããã¯é¢æ°ãå©çšå¯èœã§ãã pytestã®ããã¯ã¯ãpytestããã¥ã¡ã³ããµã€ãã«ãªã¹ããããŠããŸã ã ãã®äŸã§ã¯ããã¹ãã¹ããŒã¿ã¹ã®å€èгã倿Žãããã©ã°ã€ã³ãäœæããŸãã ã³ãã³ãã©ã€ã³ãã©ã¡ãŒã¿ãŒã远å ããŠããã®æ°ããåäœãæå¹ã«ããŸãã åºåããããŒã«ããã¹ãã远å ããŸãã ç¹ã«ããã¹ãŠã®FAILEDã¹ããŒã¿ã¹ã€ã³ãžã±ãŒã¿ïŒå€±æïŒããæ¹åã®ããã«OPPORTUNITYïŒèŠèŸŒã¿ïŒãã«å€æŽããFãOã«å€æŽããããã¹ããå®è¡ããŠããã ãããããšãããããŸãããããããŒã«è¿œå ããŸãã ãããè¡ãã«ã¯ã --niceãªãã·ã§ã³ã䜿çšããŸãã
åäœã®å€æŽããã©ã°ã€ã³ã®ã¡ã«ããºã ã®èª¬æãšã¯å¥ã«ããããã«ãconftest.pyãåé
åžå¯èœãªãã©ã°ã€ã³ã«å€ããåã«å€æŽãå ããŸãã ãã®æ¹æ³ã§ãã©ã°ã€ã³ãå®è¡ããå¿
èŠã¯ãããŸããã ããããå€ãã®å Žåã1ã€ã®ãããžã§ã¯ãã§ã®ã¿äœ¿çšããããšãæå³ãã倿Žã¯ãå
±æããŠãã©ã°ã€ã³ã«å€æããã®ã«ååã«åœ¹ç«ã¡ãŸãã ãããã£ãŠãconftest.pyãã¡ã€ã«ã«æ©èœã远å ããããšããå§ããconftest.pyã§ãã¹ãŠãæ©èœããåŸãã³ãŒããããã±ãŒãžã«ç§»åããŸãã
ã¿ã¹ã¯ãããžã§ã¯ãã«æ»ããŸãã 30ããŒãžã®ãäŸå€ã®åŸ
æ©ãã»ã¯ã·ã§ã³ã§ã¯ã誰ããAPI颿°ã誀ã£ãŠåŒã³åºããå Žåã«äŸå€ãã¹ããŒããããã©ããã確èªããããã€ãã®ãã¹ããäœæããŸããã å°ãªããšãããã€ãã®èãããããšã©ãŒç¶æ
ãèŠéããããã§ãã
ããã«ããã€ãã®ãã¹ãã瀺ããŸãã
ch5 / a / tasks_proj / tests / func / test_api_exceptions.py
 """     API wrong.""" import pytest import tasks from tasks import Task @pytest.mark.usefixtures('tasks_db') class TestAdd(): """,   tasks.add().""" def test_missing_summary(self): """  ,  summary missing.""" with pytest.raises(ValueError): tasks.add(Task(owner='bob')) def test_done_not_bool(self): """  ,  done   bool.""" with pytest.raises(ValueError): tasks.add(Task(summary='summary', done='True')) 
ããããå®è¡ããŠãåæ Œãããã©ããã確èªããŸãããã
 $ cd /path/to/code/ch5/a/tasks_proj $ pytest ===================== test session starts ====================== collected 57 items tests/func/test_add.py ... tests/func/test_add_variety.py ............................ tests/func/test_add_variety2.py ............ tests/func/test_api_exceptions.py .F....... tests/func/test_unique_id.py . tests/unit/test_task.py .... =========================== FAILURES =========================== __________________ TestAdd.test_done_not_bool __________________ self = <func.test_api_exceptions.TestAdd object at 0x103a71a20> def test_done_not_bool(self): """Should raise an exception if done is not a bool.""" with pytest.raises(ValueError): > tasks.add(Task(summary='summary', done='True')) E Failed: DID NOT RAISE <class 'ValueError'> tests/func/test_api_exceptions.py:20: Failed ============= 1 failed, 56 passed in 0.28 seconds ============== 
詳现ã«ã€ããŠã¯ã -vã§å床å®è¡ããŠã¿ãŸãããã ãã¬ãŒã¹ã¯ãã§ã«è¡šç€ºãããŠããã®ã§ã-- --tb=noæŒããŠ--tb=noãªãã«ã§ããŸãã
-k TestAddã䜿çšããæ°ãããã¹ãã«çŠç¹ãåœãŠãŸããããããã¯ããTestAddããå«ãååã®ãã¹ããä»ã«ãªãããæ©èœããŸãã
ããã¹ãŠãèœãšããŠããã®ãã¹ãã®ä¿®æ£ã詊ã¿ãããšãã§ããŸãïŒãããŠãåŸã§ãã¹ããè¡ããŸãïŒããä»åºŠã¯éçºè
ã«ãšã£ãŠå€±æãããå¿«é©ã«ããããšã«çŠç¹ãåœãŠãŸãã
ãŸããããããŒã«ãããããšãããšããã¡ãã»ãŒãžã远å ããŸããããã¯ã pytest_report_header()ãšããpytest_report_header()ããã¯ã䜿çšããŠå®è¡ã§ããŸãã
ch5 / b / tasks_proj / tests / conftest.py
 def pytest_report_header(): """    .""" return "Thanks for running the tests." 
ã瀌ã®ã¡ã¢ãå
¥åããã®ã¯æããã«æãã§ãã ãã ããããããŒã«æ
å ±ã远å ããæ©èœã¯æ¡åŒµã§ããŸãã ãŠãŒã¶ãŒåã远å ãã䜿çšããæ©åšãšãã¹ãããããŒãžã§ã³ãæå®ã§ããŸãã äžè¬ã«ãæååã«å€æã§ãããã®ã¯ãã¹ãŠãã¹ãã®ã¿ã€ãã«ã«æ¿å
¥ã§ããŸãã
次ã«ããã¹ãã¹ããŒã¿ã¹ã¬ããŒãã倿ŽããŠã FãO ã FAILEDãOPPORTUNITY for improvementãŸãã ãã®ããšãå¯èœã«ããããã¯ããããŸãïŒ pytest_report_teststatus() ïŒ
ch5 / b / tasks_proj / tests / conftest.py
 def pytest_report_teststatus(report): """   .""" if report.when == 'call' and report.failed: return (report.outcome, 'O', 'OPPORTUNITY for improvement') 
ãããŠä»ãç§ãã¡ã¯æ¢ããŠãããœãªã¥ãŒã·ã§ã³ãæã«å
¥ããŸããã --verboseãã©ã°ã䜿çšããªããã¹ãã»ãã·ã§ã³ã§ã¯ã倱æã«å¯ŸããŠOã衚瀺ãããŸããã€ãŸããæ¹åãå¯èœã§ãã
 $ cd /path/to/code/ch5/b/tasks_proj/tests/func $ pytest --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py .O ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.06 seconds ======= 
-vãŸãã¯--verboseãã©ã°ã䜿çšããæ¹ãè¯ãã§ãããïŒ
 $ pytest -v --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py::TestAdd::test_missing_summary PASSED test_api_exceptions.py::TestAdd::test_done_not_bool OPPORTUNITY for improvement ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.07 seconds ======= 
æåŸã«è¡ã倿Žã¯ãã³ãã³ãã©ã€ã³ãã©ã¡ãŒã¿ãŒ--nice,ã远å ããããšã§ã--nice,ããã«ãããã¹ããŒã¿ã¹ã®å€æŽã¯ã-- --niceã眮ãæããå Žåã«ã®ã¿çºçããŸãã
 def pytest_addoption(parser): """ nice    --nice.""" group = parser.getgroup('nice') group.addoption("--nice", action="store_true", help="nice: turn failures into opportunities") def pytest_report_header(): """    .""" if pytest.config.getoption('nice'): return "Thanks for running the tests." def pytest_report_teststatus(report): """   .""" if report.when == 'call': if report.failed and pytest.config.getoption('nice'): return (report.outcome, 'O', 'OPPORTUNITY for improvement') 
ãã®ãã©ã°ã€ã³ã§ã¯ãããã€ãã®ããã¯ãã䜿çšããªãããšã«æ³šæããŠãã ããã ã¡ã€ã³ã®Pytestããã¥ã¡ã³ããµã€ãã«ã¯ãä»ã«ã倿°ã®ãµã€ãããããŸãã
ããã§ãäŸã§ãã©ã°ã€ã³ãå®è¡ããã ãã§ããã©ã°ã€ã³ãæåã§ãã¹ãã§ããŸãã æåã«ã --niceãªãã·ã§ã³ã䜿çšããã«ããŠãŒã¶ãŒåã®ã¿ã衚瀺ãããããã«ããŸãã
 $ cd /path/to/code/ch5/c/tasks_proj/tests/func $ pytest --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== collected 9 items test_api_exceptions.py .F ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.07 seconds ======= 
--nice ïŒ
 $ pytest --nice --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py .O ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.07 seconds ======= 
--niceãš--verbose ïŒ
 $ pytest -v --nice --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py::TestAdd::test_missing_summary PASSED test_api_exceptions.py::TestAdd::test_done_not_bool OPPORTUNITY for improvement ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.06 seconds ======= 
ãããïŒ conftest.pyãã¡ã€ã«ã®çŽ10è¡ã®ã³ãŒãã§ã conftest.py倿Žããã¹ãŠè¡ããŸããã æ¬¡ã«ããã®ã³ãŒãããã©ã°ã€ã³æ§é ã«ç§»åããŸãã
ã€ã³ã¹ããŒã«å¯èœãªãã©ã°ã€ã³ãäœæãã
ãã©ã°ã€ã³ãä»ã®ãŠãŒã¶ãŒãšå
±æããããã»ã¹ã¯æç¢ºã«å®çŸ©ãããŠããŸãã ç¬èªã®ãã©ã°ã€ã³ãPyPIã«å«ããªãå Žåã§ãããã®ããã»ã¹ãå®è¡ãããšããªãŒãã³ãœãŒã¹ãã©ã°ã€ã³ããã³ãŒããèªã¿ããããªãããããã圹ç«ã€ãã©ãããè©äŸ¡ããæ©äŒãå¢ããŸãã
ãã®ãããã¯ã¯ä»ã®å Žæã§ååã«ææžåãããŠããããããã®æ¬ã§Pythonããã±ãŒãžã®ããã±ãŒãžåãšé
åžãå®å
šã«ã«ããŒããããšã¯äžèŠã§ãã ãããšãããšãã·ã¢èªã ãã ããåã®ã»ã¯ã·ã§ã³ã§äœæããããŒã«ã«æ§æãã©ã°ã€ã³ãããpipã䜿çšããŠã€ã³ã¹ããŒã«ããããã®ã«ç§»è¡ããããšã¯å€§ããããšã§ã¯ãããŸããã ã
æåã«ããã©ã°ã€ã³ã³ãŒãããã¹ãããæ°ãããã£ã¬ã¯ããªãäœæããå¿
èŠããããŸãã åŒã³æ¹ã¯é¢ä¿ãããŸãããããã€ã¹ãã©ã°çšã®ãã©ã°ã€ã³ãäœæããŠããã®ã§ãpytest-niceãšåŒã³ãŸãããã ãã®æ°ãããã£ã¬ã¯ããªã«ã¯ãpytest_nice.pyãšsetup.pyã®2ã€ã®ãã¡ã€ã«ããããŸãã ïŒãã¹ãã«ã¿ãã°ã«ã€ããŠã¯ã105ããŒãžã®ããã¹ããã©ã°ã€ã³ãã»ã¯ã·ã§ã³ã§èª¬æããŸããïŒ
 â LICENSE â pytest_nice.py â setup.py â ââââtests â conftest.py â test_nice.py 
pytest_nice.py ããã®é¢æ°ã«é¢é£ä»ããããconftest.pyã®æ£ç¢ºãªã³ã³ãã³ããé
眮ããŸãïŒãããŠtasks_proj/tests/conftest.pyããæœåºãtasks_proj/tests/conftest.py ïŒïŒ
ch5 / pytest-nice / pytest_nice.py
 """  pytest-nice .""" import pytest def pytest_addoption(parser): """ nice    --nice.""" group = parser.getgroup('nice') group.addoption("--nice", action="store_true", help="nice: turn FAILED into OPPORTUNITY for improvement") def pytest_report_header(): """    .""" if pytest.config.getoption('nice'): return "Thanks for running the tests." def pytest_report_teststatus(report): """   .""" if report.when == 'call': if report.failed and pytest.config.getoption('nice'): return (report.outcome, 'O', 'OPPORTUNITY for improvement') 
setup.pyæå°éã®setup()åŒã³åºããå¿
èŠã§ãã
ch5 / pytest-nice / setup.py
 """Setup  pytest-nice plugin.""" from setuptools import setup setup( name='pytest-nice', version='0.1.0', description=' Pytest,   FAILURE into OPPORTUNITY', url='https:////////', author=' ', author_email='your_email@somewhere.com', license='proprietary', py_modules=['pytest_nice'], install_requires=['pytest'], entry_points={'pytest11': ['nice = pytest_nice', ], }, ) 
å¹
åºããªãŒãã£ãšã³ã¹ãŸãã¯ã€ã³ã¿ãŒãããã«é
ä¿¡ããå Žåã¯ãèšå®ã§ããã«æ
å ±ãå¿
èŠã«ãªããŸãã ãã ããå°ããªããŒã ã®å Žåãèªåèªèº«ã®å Žåã¯ããã§ååã§ãã
setup()ä»ã®ãã©ã¡ãŒã¿ãŒãå«ããããšãã§ããŸãã ããã«ã¯å¿
é ãã£ãŒã«ãã®ã¿ããããŸãã ããŒãžã§ã³ãã£ãŒã«ãã¯ããã®ãã©ã°ã€ã³ã®ããŒãžã§ã³ã§ãã ãããŠãããªããããŒãžã§ã³ãç«ã¡äžãããšããããã¯å®å
šã«ããªã次第ã§ãã URLãã£ãŒã«ãã¯å¿
é ã§ãã 空çœã®ãŸãŸã«ã§ããŸãããèŠåã衚瀺ãããŸãã author_emailãšauthor_emailã¯ã maintainerãšmaintainer_email眮ãæããããšãã§ããŸããããããã®ãã¢ã®ãããããååšããã¯ãã§ãã licenseãã£ãŒã«ãã¯çãããã¹ããã£ãŒã«ãã§ãã ããã¯ãå€ãã®ãªãŒãã³ãœãŒã¹ã©ã€ã»ã³ã¹ã®1ã€ãããªãã®ååãäŒç€ŸããŸãã¯ããªãã«é©ãããã®ã§ãã py_modulesã¯ããã®ãã©ã°ã€ã³ã®å¯äžã®ã¢ãžã¥ãŒã«ãšããŠpy_modulesãªã¹ããããŠããŸãã ããã¯ãªã¹ãã§ãããè€æ°ã®ã¢ãžã¥ãŒã«ãå«ããããšãã§ããŸãããè€æ°ããå Žåã¯ãããã±ãŒãžã䜿çšããŠãã¹ãŠã®ã¢ãžã¥ãŒã«ã1ã€ã®ãã£ã¬ã¯ããªã«é
眮ããŸãã
ãããŸã§ã®ãšããããã¹ãŠã®setup()ãªãã·ã§ã³ã¯æšæºã§ããããã¹ãŠã®Pythonã€ã³ã¹ããŒã©ãŒã«ãã£ãŠäœ¿çšãããŸãã Pytestãã©ã°ã€ã³ã§ç°ãªãéšåã¯ã entry_pointsãã©ã¡ãŒã¿ãŒã§ãã entry_points={'pytest11': ['nice = pytest_nice', ], },.ããªã¹ããentry_points={'pytest11': ['nice = pytest_nice', ], },. entry_points颿°ã¯setuptoolsæšæºã§ãããpytest11ã¯pytestãæ¢ããŠããç¹å¥ãªèå¥åã§ãã ãã®è¡ã§ã¯ã niceã¯ãã©ã°ã€ã³ã®ååã§ããã pytest_niceãã©ã°ã€ã³ãååšããã¢ãžã¥ãŒã«pytest_niceååã§ããããšãpytestã«äŒããŸãã ããã±ãŒãžã䜿çšããå Žåãããã§ã®ãšã³ããªã¯æ¬¡ã®ããã«ãªããŸãã
README.rstãã¡ã€ã«ã«ã€ããŠã¯README.rst話ããŠREADME.rst ã äœããã®åœ¢åŒã®READMEãsetuptoolsã®èŠä»¶ã§ãã ã¹ããããããšããããåŸãããŸãïŒ
 ... warning: sdist: standard file not found: should have one of README, README.rst, README.txt ... 
ãšã«ããããããžã§ã¯ãæ
å ±ãå«ããããã®æšæºçãªæ¹æ³ãšããŠREADMEãä¿æããããšã¯è¯ãèãã§ãã pytest-niceã®ãã¡ã€ã«ã«å
¥ãããã®ã¯æ¬¡ã®ãšããã§ãã
ch5 / pytest-nice / README.rst
 pytest-nice : A pytest plugin =============================   pytest     .  -------- -   ,     pytest. -  ``--nice`` , : -  ``F``  ``O`` -  ``-v``,  ``FAILURE``  ``OPPORTUNITY for improvement``  ------------ ,    Pytest    .tar.gz    PATH,  : :: $ pip install PATH/pytest-nice-0.1.0.tar.gz $ pip install --no-index --find-links PATH pytest-nice  ----- :: $ pytest --nice 
READMEãã¡ã€ã«ã®å
容ã«ã€ããŠå€ãã®æèŠããããŸãã ããã¯å€§å¹
ã«ããªãã³ã°ãããããŒãžã§ã³ã§ãããåäœããŸãã
ãã©ã°ã€ã³ã®ãã¹ã
ãã©ã°ã€ã³ã¯ãä»ã®ã³ãŒããšåæ§ã«ãã¹ãããå¿
èŠãããã³ãŒãã§ãã ãã ãããã¹ãããŒã«ãžã®å€æŽã®ãã¹ãã¯ããå°ãè€éã§ãã 98ããŒãžã®ãç¬èªã®ãã©ã°ã€ã³ã®äœæãã»ã¯ã·ã§ã³ã§ãã©ã°ã€ã³ã³ãŒããéçºãããšãããµã³ãã«ãã¹ããã¡ã€ã«ã䜿çšããŠæåã§ãã§ãã¯ããpytestãå®è¡ããŠãåºåãæ£ããããšã確èªããŸããã pytesterã«ä»å±ããŠãããããã©ã«ãã§ã¯ç¡å¹ã«ãªã£ãŠããpytesterãšãããã©ã°ã€ã³ã䜿çšããŠãèªåã¢ãŒãã§ãåãããšãã§ããŸãã
pytest-niceã®ãã¹ããã£ã¬ã¯ããªã«ã¯ãconftest.pyãštest_nice.pyã®2ã€ã®ãã¡ã€ã«ããããŸãã pytesterã䜿çšããã«ã¯ã pytesterã«1è¡ã ã远å ããå¿
èŠãããconftest.py ã
ch5 / pytest-nice / tests / conftest.py
 """pytester is needed for testing plugins.""" pytest_plugins = 'pytester' 
ãã®è¡ã«ã¯ã pytesterãã©ã°ã€ã³ãå«ãŸããŠpytesterãŸãã testdirãšãããã£ã¯ã¹ãã£ã䜿çšããŸãã pytester ã pytesterãªã³ã«ãªã£ããšãã«äœ¿çšå¯èœã«ãªããŸãã
å€ãã®å Žåããã©ã°ã€ã³ã®ãã¹ãã¯ãæåã§èª¬æãã圢åŒãåããŸãã
- ãµã³ãã«ã®ãã¹ããã¡ã€ã«ãäœæããŸãã
- ãµã³ãã«ãã¡ã€ã«ãå«ããã£ã¬ã¯ããªã§ããã€ãã®ãã©ã¡ãŒã¿ãŒã䜿çšããŠããŸãã¯äœ¿çšããã«pytestãå®è¡ããŸãã
- åºåã確èªããŠãã ããã
- å¯èœãªå Žåãçµæã³ãŒãããã§ãã¯ããã«ã¯ããã¹ãŠã®ãã¹ã§0ãäžéšã®å€±æã§1ã«ãªããŸãã
1ã€ã®äŸãèŠãŠã¿ãŸãããã
ch5 / pytest-nice / tests / test_nice.py
 def test_pass_fail(testdir):  
Fixture testdirã¯ããã¹ããã¡ã€ã«ããã¹ãããããã®äžæãã£ã¬ã¯ããªãèªåçã«äœæããŸãã makepyfile() , . : , , .
pytest testdir.runpytest() . , . RunResult .
stdout ret . , , , fnmatch_lines , , , , ret 0 1 . , fnmatch_lines , . . , , :
ch5/pytest-nice/tests/test_nice.py
 @pytest.fixture() def sample_test(testdir): testdir.makepyfile(""" def test_pass(): assert 1 == 1 def test_fail(): assert 1 == 2 """) return testdir 
, , sample_test , . :
ch5/pytest-nice/tests/test_nice.py
 def test_with_nice(sample_test): result = sample_test.runpytest('--nice') result.stdout.fnmatch_lines(['*.O', ])  
. , :
ch5/pytest-nice/tests/test_nice.py
 def test_header(sample_test): result = sample_test.runpytest('--nice') result.stdout.fnmatch_lines(['Thanks for running the tests.']) def test_header_not_nice(sample_test): result = sample_test.runpytest() thanks_message = 'Thanks for running the tests.' assert thanks_message not in result.stdout.str() 
, , .
:
ch5/pytest-nice/tests/test_nice.py
 def test_help_message(testdir): result = testdir.runpytest('--help')  
, , , .
pytest-nice , . .zip.gz , :
 $ cd /path/to/code/ch5/pytest-nice/ $ pip install . Processing /path/to/code/ch5/pytest-nice Requirement already satisfied: pytest in /path/to/venv/lib/python3.6/site-packages (from pytest-nice==0.1.0) Requirement already satisfied: py>=1.4.33 in /path/to/venv/lib/python3.6/site-packages (from pytest->pytest-nice==0.1.0) Requirement already satisfied: setuptools in /path/to/venv/lib/python3.6/site-packages (from pytest->pytest-nice==0.1.0) Building wheels for collected packages: pytest-nice Running setup.py bdist_wheel for pytest-nice ... done ... Successfully built pytest-nice Installing collected packages: pytest-nice Successfully installed pytest-nice-0.1.0 
, , :
 $ pytest -v ===================== test session starts ====================== plugins: nice-0.1.0 collected 7 items tests/test_nice.py::test_pass_fail PASSED tests/test_nice.py::test_with_nice PASSED tests/test_nice.py::test_with_nice_verbose PASSED tests/test_nice.py::test_not_nice_verbose PASSED tests/test_nice.py::test_header PASSED tests/test_nice.py::test_header_not_nice PASSED tests/test_nice.py::test_help_message PASSED =================== 7 passed in 0.34 seconds =================== 
ãæ³šæ : , . .
 platform win32 -- Python 3.6.5, pytest-3.9.3, py-1.7.0, pluggy-0.8.0 -- c:\venv36\scripts\python.exe collected 7 items tests/test_nice.py::test_pass_fail FAILED [ 14%] tests/test_nice.py::test_with_nice OPPORTUNITY for improvement [ 28%] tests/test_nice.py::test_with_nice_verbose OPPORTUNITY for improvement [ 42%] tests/test_nice.py::test_not_nice_verbose FAILED [ 57%] tests/test_nice.py::test_header PASSED [ 71%] tests/test_nice.py::test_header_not_nice PASSED [ 85%] tests/test_nice.py::test_help_message PASSED [100%] ================================== FAILURES =================================== _______________________________ test_pass_fail ________________________________ 
  result.stdout.fnmatch_lines([ '*.F', # . for Pass, F for Fail ]) 
ã«
  result.stdout.fnmatch_lines([ '*.F*', # . for Pass, F for Fail ]) 
* F
test_with_nice , test_with_nice_verbose , test_not_nice_verbose
pytest.
c
'test_with_nice.py .O [100%]'
.
,
RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead
!
 (venv36) c:\_BOOKS_\pytest_si\bopytest-code\code\ch5\pytest-nice>pytest -v ============================= test session starts ============================= platform win32 -- Python 3.6.5, pytest-3.9.3, py-1.7.0, pluggy-0.8.0 -- c:\venv36\scripts\python.exe cachedir: .pytest_cache rootdir: c:\_BOOKS_\pytest_si\bopytest-code\code\ch5\pytest-nice, inifile: plugins: nice-0.1.0 collected 7 items tests/test_nice.py::test_pass_fail PASSED [ 14%] tests/test_nice.py::test_with_nice PASSED [ 28%] tests/test_nice.py::test_with_nice_verbose PASSED [ 42%] tests/test_nice.py::test_not_nice_verbose PASSED [ 57%] tests/test_nice.py::test_header PASSED [ 71%] tests/test_nice.py::test_header_not_nice PASSED [ 85%] tests/test_nice.py::test_help_message PASSED [100%] ============================== warnings summary =============================== tests/test_nice.py::test_pass_fail c:\venv36\lib\site-packages\_pytest\compat.py:332: RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead return getattr(object, name, default) 
ãã£ãïŒ . (pytest-nice), Python
pytest-:
 $ pip uninstall pytest-nice Uninstalling pytest-nice-0.1.0: Would remove: \path\to\venv\lib\site-packages\pytest_nice-0.1.0.dist-info\* ... Proceed (y/n)? y Successfully uninstalled pytest-nice-0.1.0 
â , pytest, PyPI.
, . , setup.py :
 $ cd /path/to/code/ch5/pytest-nice $ python setup.py sdist running sdist running egg_info creating pytest_nice.egg-info ... running check creating pytest-nice-0.1.0 ... creating dist Creating tar archive ... $ ls dist pytest-nice-0.1.0.tar.gz 
( , sdist source distribution â â .â)
pytest-nice dist pytest-nice-0.1.0.tar.gz .
, , :
 $ pip install dist/pytest-nice-0.1.0.tar.gz Processing ./dist/pytest-nice-0.1.0.tar.gz ... Installing collected packages: pytest-nice Successfully installed pytest-nice-0.1.0 
.tar.gz , .
pip , , , , , , .tar.gz . , pytest-nice-0.1.0.tar.gz myplugins .
pytest-nice myplugins :
 $ pip install --no-index --find-links myplugins pytest-nice 
--no-index pip PyPI, , .
The --find-links myplugins tells PyPI to look in myplugins for packages to install. And of course, pytest-nice is what we want to install.
--find-links myplugins PyPI myplugins . , pytest-nice â , .
myplugins , , --upgrade :
 $ pip install --upgrade --no-index --find-links myplugins pytest-nice 
pip , --no-index --find-links myplugins .
PyPI
, , . , . , , , Python Packaging .
pytest, â cookiecutter-pytest-plugin :
 $ pip install cookiecutter $ cookiecutter https://github.com/pytest-dev/cookiecutter-pytest-plugin 
. , . ; , , . pytest, , .
ch4/cache/test_slower.py autouse fixture, check_duration() . 4. .
- pytest-slower, , , « » . 102.
- , pytest-slower , .
- ãã©ã°ã€ã³ã®ãã¹ãã³ãŒããäœæããŸãã
- èŠãŠã¿ãŸãããPythonã®ããã±ãŒãžã€ã³ããã¯ã¹ããšÂ«pytest-Â»ãæ¢ããŸãããããããããªpytestãã©ã°ã€ã³ãèŠã€ããŠãã ããã
- éžæãããã©ã°ã€ã³ãã€ã³ã¹ããŒã«ããã¿ã¹ã¯ãã¹ãã§è©ŠããŠãã ããã
次ã¯äœã§ãã
conftest.pyãã®æ¬ã§ã¯ãããŸã§äœåºŠã䜿çšããŸãããããšãã°ãpytestã®å®è¡ã«åœ±é¿ããèšå®ãã¡ã€ã«ããããŸãpytest.iniãæ¬¡ã®ç« ã§ã¯ãããŸããŸãªæ§æãã¡ã€ã«ã«ç²Ÿéãããã¹ãæã«çæŽ»ãæ¥œã«ããããã«ã§ããããšãèŠã€ããŸãã
 æ»ã 次ãž
 æ»ã 次㞠