5

(Python 2.7)コードがdoctestで実行されているかどうかを認識させるにはどうすればよいですか?

シナリオは次のとおりです。print()引数として渡されたファイル記述子への出力を次のように行う関数があります。

from __future__ import print_function

def printing_func(inarg, file=sys.stdout):
    # (do some stuff...)
    print(result, file=file)

しかしprinting_func()、doctestで使用しようとすると、テストは失敗します。fileを呼び出すときにキーワード引数を指定したため、出力はdoctestモジュールによって設定されたデフォルトの出力リダイレクトではなく、print()実際にになりsys.stdout、doctestは出力を認識しません。

ではprinting_func()、それがdoctest内で実行されているかどうかを確認して、file呼び出し時にキーワード引数を渡さないようにするにはどうすればよいprint()でしょうか。

4

4 に答える 4

4

Nitenのバージョンはinside_doctest広すぎるようです。sys.stdoutロギングまたはdoctest以外のフレームワークでテストする場合に、再定義することはそれほど珍しいことではないため、誤検知が発生します。

より狭いテストは次のようになります。

import sys

def in_doctest():
    """
Determined by observation
    """
    if '_pytest.doctest' in sys.modules:
        return True
    ##
    if hasattr(sys.modules['__main__'], '_SpoofOut'):
        return True
    ##
    if sys.modules['__main__'].__dict__.get('__file__', '').endswith('/pytest'):
        return True
    ##
    return False


def test():
    """
    >>> print 'inside comments, running in doctest?', in_doctest()
    inside comments, running in doctest? True
    """
    print 'outside comments, running in doctest?', in_doctest()

if __name__ == '__main__':
    test()

in_doctest_SpoofOutdoctestがを置き換えるために使用するクラスのテストsys.stdout。同じ方法で検証できるdoctestモジュールの他の属性があります。別のモジュールが名前を再利用するのを防ぐことができるわけではありませんが、この名前は一般的ではないので、おそらくまともなテストです。

上記をtest.pyに入れてください。非doctestモードで実行すると、次のようになりますpython test.py

outside comments, running in doctest? False

doctest冗長モードで実行すると、次のようになりpython -m doctest test.py -vます。

Trying:
    print 'inside comments, running in doctest?', in_doctest()
Expecting:
    inside comments, running in doctest? True
ok

コードにdoctestを認識させることは一般的に悪い考えであるという、他の人のコメントに同意します。私はややエキゾチックな状況でのみそれを行いました-手動で効率的に作成するには多すぎるため、コードジェネレーターを介してテストケースを作成する必要がありました。しかし、あなたがそれをする必要があるならば、上記はそれのためのまともなテストです。

于 2014-03-29T17:41:19.303 に答える
1

私は読んだ後に答えを見つけましたdoctest.py; 後世のためにここに投稿...

Doctestは、新しいファイル記述子をに割り当てることにより、標準出力をリダイレクトしますsys.stdout。問題は、sys.stdoutdoctestが再定義される前に、関数の説明が元のファイル記述子の値を閉じていたことでした。

代わりに、私が次のことをした場合:

def printing_func(inarg, file=None):
    # (do some stuff...)

    if file is None:
        file = sys.stdout

    print(result, file=file)

次に、ではなくモジュールprinting_func()をキャプチャし、実行すると、テスト内で実行されている場合からdoctestの再定義された属性を取得します。syssys.stdoutstdoutsys

編集:これにより、doctest内で実行されているかどうかを簡単に確認することもできます。

def inside_doctest(original_stdout=sys.stdout):
    return original_stdout != sys.stdout
于 2011-11-14T01:06:42.560 に答える
0

FWIW(そして遅れて冗長になって申し訳ありません)多くの開発者は「iftest」をアンチパターンと見なしています。

つまり、テスト対象のコードが「実際に」実行されたときとテストされたときで異なることを行う場合は、問題が発生していることになります。あなたが正当な理由でそれをしているとあなたが信じているとしても。したがって、上記のコメントは、それを行わないソリューションを称賛しています。「iftest」パターンを使用したいときは、必要がないようにリファクタリングを試みます。

于 2013-12-14T20:12:41.440 に答える
0

モジュール「doctest」がロードされているかどうかを確認するだけです。

def in_doctest():
    import sys
    return 'doctest' in sys.modules
于 2019-01-16T17:18:55.683 に答える