1

subprocess.call() を使用する Python コードの一部をテストしているため、その関数呼び出しを制御できません。アサーションを実行するには、そのシステム コールからの出力をキャプチャする必要があります。os.stdout を StringIO オブジェクトに設定しようとしましたが、システム コールの出力がキャプチャされません。この問題を解決するにはどうすればよいですか? これまでの私のコードは次のとおりです。

テストするコード (私はこれを制御できません):

def runFile(filename):
    check_call("./" + filename)

システムコール出力をキャプチャする私の試み:

import StringIO
oldout = sys.stdout
try:
    sys.stdout = StringIO.StringIO()
    runFile("somefile")
    output = sys.stdout.getvalue()
    assert output == "expected-output"
finally:
    sys.stdout = oldout
4

2 に答える 2

1

独自の標準出力をリダイレクトできます

rd, wr = os.pipe()
oldstdout = os.dup(1)
os.dup2(wr, 1)
os.close(wr)

rd外部プロセスの実行中に読み取ります。

外部プロセスがパイプ バッファに収まる以上の書き込みを行う可能性があるため、これは機能しない可能性があります。この場合、読み取りスレッドを生成する必要があります。

その後、古い状態を復元します

os.dup2(oldstdout, 1)
os.close(oldstdout)
os.close(rd)

そして普通に続けます。

于 2012-06-02T10:31:57.757 に答える
0

モジュールはsubprocessを使用して出力ストリームに直接書き込むため、os.write変更sys.stdoutしても何も起こりません。

そのため、一般に表記を使用して subprocess モジュールで使用される出力ストリームを指定する必要があり、書き込み先の fileno がないため、出力ファイルとして...([cmd, arg, ...], stdout=output_file, ...)使用できないのはなぜですか。StringIO

したがって、やりたいことを達成する唯一の方法は、テストする必要があるモジュールをインポートする前にmonkeypatchすることです。これにより、 check_outputsubproces.check_callのように機能します。

例えば:

import subprocess

def patched_call(*popenargs, **kwargs):
    if 'stdout' in kwargs:
        raise ValueError('stdout argument not allowed, it will be overridden.')
    process = subprocess.Popen(*popenargs, stdout=subprocess.PIPE, **kwargs)
    output, unused_err = process.communicate()
    # do something with output here
    retcode = process.poll()
    if retcode:
        cmd = kwargs.get("args")
        if cmd is None:
            cmd = popenargs[0]
        raise CalledProcessError(retcode, cmd, output=output)
    return retcode

subprocess.check_call = patched_call
于 2012-06-02T09:15:18.900 に答える