web-dev-qa-db-ja.com

docstringを使用して、py.testのテストを一覧表示します

簡単なテストファイルは次のとおりです。

_# test_single.py
def test_addition():
    "Two plus two is still four"
    assert 2 + 2 == 4

def test_addition2():
    "One plus one is still two"
    assert 1 + 1 == 2
_

Py.testのデフォルトの出力は次のようになります

_$ py.test test_single.py -v
[...]
test_single.py::test_addition PASSED
test_single.py::test_addition2 PASSED
_

私はを頂きたい

_Two plus two is still four PASSED
One plus one is still two PASSED
_

つまり、テストの説明としてdocstringを使用します。

_conftest.py_ファイルでカスタマイズを使用しようとしました:

_import pytest

@pytest.mark.tryfirst
def pytest_runtest_makereport(item, call, __multicall__):
    # execute all other hooks to obtain the report object
    rep = __multicall__.execute()
    if rep.when == "call":
        extra = item._obj.__doc__.strip()
        rep.nodeid =  extra
    return rep
_

これは近いですが、すべての行でファイル名が繰り返されます。

_$ py.test test_single.py
======================================================================================== test session starts =========================================================================================
platform darwin -- Python 2.7.7 -- py-1.4.26 -- pytest-2.6.4
plugins: greendots, osxnotify, pycharm
collected 2 items

test_single.py
And two plus two is still four .
test_single.py
And one plus one is still two .

====================================================================================== 2 passed in 0.11 seconds ======================================================================================
_

出力に_test_single.py_が含まれる行を回避するにはどうすればよいですか、または1回だけ印刷するにはどうすればよいですか?

Py.testのソースとそのプラグインのいくつかを調べても役に立ちませんでした。

pytest-spec プラグインを知っていますが、関数の名前を説明として使用しています。 def test_two_plus_two_is_four()を書きたくありません。

20
Matthias Berth

@ michael-wanの答えへの私のコメントを拡張するには:specpluginに似た何かを達成するためにconftest.py

def pytest_itemcollected(item):
    par = item.parent.obj
    node = item.obj
    pref = par.__doc__.strip() if par.__doc__ else par.__class__.__name__
    suf = node.__doc__.strip() if node.__doc__ else node.__name__
    if pref or suf:
        item._nodeid = ' '.join((pref, suf))

およびのpytest出力

class TestSomething:
"""Something"""

def test_ok(self):
    """should be ok"""
    pass

次のようになります

py.test screen grab

Docstringを省略すると、クラス/関数名が使用されます。

19

私は行方不明でしたrspec in Rubypythonの場合。したがって、プラグインに基づいてpytest-testdox.、レポートメッセージとしてドキュメント文字列を受け取る同様のものを作成しました。あなたはそれをチェックすることができます pytest-pspecenter image description here

5
7H3 IN5ID3R

(私が思うに)箱から出してやりたいことをするプラグインについては、 pytest-testdox をチェックしてください。

これは、各テスト関数名のわかりやすい形式のリストを提供し、test_を削除し、アンダースコアをスペースに置き換えて、テスト名を読みやすくします。また、テストファイルごとにセクションを分割します。

出力は次のようになります。

enter image description here

4
Symmetric

@Matthias Berth、pytest_itemcollectedを使用してみることができます

def pytest_itemcollected(item):
""" we just collected a test item. """
    item.setNodeid('' if item._obj.__doc__ is None else item._obj.__doc__.strip() )

pydir/Lib/site-packages/pytest-2.9.1-py2.7.Egg/_pytest/unittest.pyを変更し、次の関数をTestCaseFunctionクラスに追加します。

def setNodeid(self, value):
    self._nodeid = value

結果は次のようになります:

platform win32 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- D:\Python27\python.exe
cachedir: .cache
rootdir: E:\workspace\satp2\atest\testcase\Search\grp_sp, inifile:
plugins: html-1.8.0, pep8-1.0.6
collecting 0 itemsNone
collected 2 items
Two plus two is still four <- sut_amap3.py PASSED
One plus one is still two <- sut_amap3.py PASSED

enter image description here ちなみに、pytest-htmlを使用している場合は、作成したpytest_runtest_makereport関数を使用すると、カスタマイズした名前でレポートが生成されます。お役に立てれば。

2
Michael Wan

私は同じことをしたかったのですが、もっと簡単な方法で、できれば必要以上のことをするための外部プラグインなしで、他のものを壊す可能性があるのでnodeidの変更を避けました

私は次の解決策を思いついた:

test_one.py

import logging

logger = logging.getLogger(__name__)

def test_one():
    """ The First test does something """
    logger.info("One")

def test_two():
    """ Now this Second test tests other things """
    logger.info("Two")

def test_third():
    """ Third test is basically checking crazy stuff """
    logger.info("Three")

conftest.py

import pytest
import inspect

@pytest.mark.trylast
def pytest_configure(config):
    terminal_reporter = config.pluginmanager.getplugin('terminalreporter')
    config.pluginmanager.register(TestDescriptionPlugin(terminal_reporter), 'testdescription')

class TestDescriptionPlugin:

    def __init__(self, terminal_reporter):
        self.terminal_reporter = terminal_reporter
        self.desc = None

    def pytest_runtest_protocol(self, item):
        self.desc = inspect.getdoc(item.obj)

    @pytest.hookimpl(hookwrapper=True, tryfirst=True)
    def pytest_runtest_logstart(self, nodeid, location):
        if self.terminal_reporter.verbosity == 0:
            yield
        else:
            self.terminal_reporter.write('\n')
            yield
            if self.desc:
                    self.terminal_reporter.write(f'\n{self.desc} ')

--verboseで実行

============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.1.dev62+g2d9dac95e, py-1.8.1, pluggy-0.13.1 -- C:\Users\Victor\PycharmProjects\pytest\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Victor\PycharmProjects\pytest, inifile: tox.ini
collecting ... collected 3 items


test_one.py::test_one 
The First test does something  PASSED                                    [ 33%]

test_one.py::test_two 
Now this Second test tests other things  PASSED                          [ 66%]

test_one.py::test_third 
Third test is basically checking crazy stuff  PASSED                     [100%]

============================== 3 passed in 0.07s ==============================

--log-cli-level=INFOで実行

============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.1.dev62+g2d9dac95e, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Victor\PycharmProjects\pytest, inifile: tox.ini
collected 3 items


test_one.py::test_one 
The First test does something  
-------------------------------- live log call --------------------------------
INFO     test_one:test_one.py:7 One
PASSED                                                                   [ 33%]

test_one.py::test_two 
Now this Second test tests other things  
-------------------------------- live log call --------------------------------
INFO     test_one:test_one.py:11 Two
PASSED                                                                   [ 66%]

test_one.py::test_third 
Third test is basically checking crazy stuff  
-------------------------------- live log call --------------------------------
INFO     test_one:test_one.py:15 Three
PASSED                                                                   [100%]

============================== 3 passed in 0.07s ==============================

conftest.pyのプラグインは、おそらく誰でも自分のニーズに応じてカスタマイズできるほど単純です。

0
SuperGeo