3

stdoutに書き込む約500行のPythonプログラムがあります(printステートメントを使用)。ここで、いくつかの変更を加えてプログラムのリファクタリングを実行したいと思いますが、その過程で、同じ出力(もちろん、同じ入力が与えられた場合)を取得し続けることを確認したいと思います。

print現在の-ingの代わりに文字列を返すように関数を書き直さずに(テストを簡単にするために)、そうするための良い戦略は何でしょうか?

(変更を開始する前に)初期出力をテキストファイルにリダイレクトすることを考えました。次に、変更したプログラムの出力をテキストファイルで簡単かつ自動的に確認するにはどうすればよいですか(その出力を一時的なテキストファイルに再度リダイレクトしてファイルを比較することなく)?

編集:これは私が決めた解決策です:

def test_something():
    # using lambda because we might test function with parameters
    f = lambda: thing_to_test
    test_generic('expect_output.txt', f)

def test_generic(filename_expected, function_to_test):

    #Run and write to tmp file
    tmpfile = 'test-tmp.txt'
    sys.stdout = open(tmpfile, 'w')
    function_to_test()
    sys.stdout = sys.__stdout__

    #compare with expected output
    expected = open(filename_expected).read()
    result = open(tmpfile).read()
    d = difflib.Differ()
    diff = d.compare(expected.splitlines(), result.splitlines())

    #print result (different lines only)
    diff_lines_only = [line for line in diff if line[0] in "+-?"]
    if not diff_lines_only:
        print "Test succeeded (%s)\n" % filename_expected
        os.remove(tmpfile)
    else:
        print "Test FAILED (%s):\n" % filename_expected
        print '\n'.join(list(diff_lines)) 

編集2:実際、私doctestが以下の答えとして提供した解決策ははるかに優れていると思います。

4

4 に答える 4

2

プログラムリダイレクトの出力を表す文字列を取得できますsys.stdout。出力を比較するには、difflibモジュールを使用できます。特に、クラスはコマンドが行うDifferことを多かれ少なかれ行います。diff

>>> import difflib
>>> text = '''bar
... baz
... '''
>>> text2 = '''foo
... bar
... '''
>>> d = difflib.Differ()
>>> for line in d.compare(text.splitlines(), text2.splitlines()):
...     print line
... 
+ foo
  bar
- baz

私が間違っていない場合、unittest2はassertEqualすでに文字列の違いを表示しようとしますが、どのレベルで、出力が十分に単純であるかはわかりません。

于 2012-11-08T20:12:27.797 に答える
1

Bashを実行していると仮定すると、を実行できますdiff -u orig-file <(python my-program.py)。これにより、元のファイル(元の出力を既に書き込んだファイル)と、プログラムが書き出す名前付きパイプとの差分が作成されます。

echoこれは、実際のP​​ythonスクリプトの代わりに使用する簡単な例です。

$ diff -u <(echo $'foo\nbar\nbaz') <(echo $'foo\nbar\nquux')
--- /dev/fd/63  2012-11-08 15:07:09.000000000 -0500
+++ /dev/fd/62  2012-11-08 15:07:09.000000000 -0500
@@ -1,3 +1,3 @@
 foo
 bar
-baz
+quux
于 2012-11-08T20:05:16.147 に答える
1

興味深い小さな例の質問-pytestを使用して印刷/キャプチャ/diffcompareソリューションを作成するためにそれを取りました。この例ではpytest機能を高度に使用していますが、これらはリンクされて完全に文書化されており、他の多くの状況でも役立ちます。事実上、このソリューションに必要なコードは現在のトップソリューションの半分未満であり、テストやその他のpytest機能のいくつかを選択的に実行できると便利な場合があります。

于 2012-11-09T10:35:17.377 に答える
1

doctestライブラリを使用したソリューション。これは、テストコードと期待される出力が1つのファイルにまとめられているため、実際にははるかに優れており、自己完結型であると私は考えています。

Pythonスクリプト(実際には、メインプログラムに含めており、最初のコマンドライン引数として「test」を指定すると実行されます):

import doctest
doctest.testfile('test-program.txt', optionflags = doctest.NORMALIZE_WHITESPACE)

そして、テストファイルtest-program.txtは次のようになります。

>>> import my_python_script
>>> whatever_I want_to_test_or_call_goes_here
and_here_I pasted_the_expected_output

これには、すべての機能(より詳細な出力へdoctestの切り替えなど)にアクセスできるという追加の利点があります。-vしたがって、完全なレポートを取得するには、コマンドラインから次の手順を実行するだけです。

 C:\wherever> python my_python_script test -v
于 2012-11-09T10:44:00.700 に答える