標準的な技術は、標準sys.stdin
とsys.stdout
の希望の項目を嘲笑います。 Python 3との互換性を気にしない場合は、StringIO
モジュールを使用することができます。しかし、先を考えてPython 2.7と3.3+に制限したい場合は、Python 2とPython 3の両方をこのようにサポートすることもできますio
モジュールを介して多くの作業が行われます(ただし、少し変更する必要がありますが、この考えは今のところは間違いです)。
すでにunittest.TestCase
があると仮定して、sys.stdin
/sys.stdout
を置き換えたユーティリティ関数(または同じクラスのメソッド)を作成できます。まず輸入:
import sys
import io
import unittest
が私の最近のプロジェクトの一つで、私はそれがユーザー(またはパイプを介して他のプログラム)はSTDINとしてあなたに入ります入力のstr
を取るSTDIN、のためにこれをやりました:両方の場合において、それはテストケースインスタンスを受け入れ、そのaddCleanup
方法THAを呼び出すこと
def stub_stdouts(testcase_inst):
stderr = sys.stderr
stdout = sys.stdout
def cleanup():
sys.stderr = stderr
sys.stdout = stdout
testcase_inst.addCleanup(cleanup)
sys.stderr = StringIO()
sys.stdout = StringIO()
注:stdoutとstderrとして
def stub_stdin(testcase_inst, inputs):
stdin = sys.stdin
def cleanup():
sys.stdin = stdin
testcase_inst.addCleanup(cleanup)
sys.stdin = StringIO(inputs)
tは、テストメソッドの期間が終了したときの位置にリセットする関数呼び出しを追加します。結果は、テストケースで最後に呼び出されてからsys.stdout
までの間、友人はio.StringIO
バージョンに置き換えられます。つまり、値を簡単に確認でき、混乱を避けることを心配する必要はありません後ろに。
例としてこれを示すことをお勧めします。 StringIO
クラスがStringIO
モジュールからのものである場合はPython 2には、このテストは唯一合格し、今
class ExampleTestCase(unittest.TestCase):
def test_example(self):
stub_stdin(self, '42')
stub_stdouts(self)
example()
self.assertEqual(sys.stdout.getvalue(), '42\n')
を、とPython 3にはそのようなモジュールが存在しない:これを使用するには、単にそのようなテストケースを作成することができます。あなたができることは、io
モジュールのバージョンを使用して、入力を受け入れるという点で若干寛大になるように修正します。これにより、例外をトリガーするのではなく、ユニコードのエンコード/デコードが自動的に行われます(print
ステートメントPython 2でうまく動作しません。私は、通常のPython 2と3の間の相互互換性のため、この操作を行います。
class StringIO(io.StringIO):
"""
A "safely" wrapped version
"""
def __init__(self, value=''):
value = value.encode('utf8', 'backslashreplace').decode('utf8')
io.StringIO.__init__(self, value)
def write(self, msg):
io.StringIO.write(self, msg.encode(
'utf8', 'backslashreplace').decode('utf8'))
は今、あなたはあなたの自己は、ユニットテストに含まれます、一つのファイルにあなたの例の機能に加えて、この答えでは、すべてのコードはプラグのPython 2の両方で動作すると、 3(ただし、Python 3ではprint
を関数として呼び出す必要があります)、stdioに対してテストを行います。
もう1つの注意:stub_
ファンクションコールは、すべての単一テストメソッドで必要とされる場合はsetUp
メソッドTestCase
に入れることができます。
もちろん、stdin/stdoutをスタブアウトするためにさまざまなモック関連ライブラリを使用したい場合は自由ですが、これはあなたの目標であれば外部依存関係に依存しません。あなたの第二の問題については
、テストケースは、彼らがメソッド内にカプセル化されなければならないとクラスレベルで、あなたの元の例は失敗しますない特定の方法、で記述される必要があります。しかし、あなたはこのような何かをしたいかもしれません:
class Test(unittest.TestCase):
def helper(self, data, answer, runner):
stub_stdin(self, data)
stub_stdouts(self)
runner()
self.assertEqual(sys.stdout.getvalue(), answer)
self.doCleanups() # optional, see comments below
def test_various_inputs(self):
data_and_answers = [
('hello', 'HELLOhello'),
('goodbye', 'GOODBYEgoodbye'),
]
runScript = upperlower # the function I want to test
for data, answer in data_and_answers:
self.helper(data, answer, runScript)
あなたがdoCleanups
を呼び出したいかもしれない理由は、すべてのdata_and_answers
ペアがあるほど深くなってからクリーンアップスタックを防ぐためですが、それはオフにすべてをポップアップ表示されますクリーンアップのスタックので、最後にクリーンアップする必要がある他のものがあった場合、これは問題に終わる可能性があります - あなたはすべてのstdio関連オブジェクトが同じ順序で最後に復元されるので、 、本当のものはいつもそこにいます。今、私がテストしたかった機能:
def upperlower():
raw = raw_input()
print (raw.upper() + raw),
私は役立つかもしれなかった何のための説明のそうです、ビット:TestCase
クラス内で覚えては、フレームワークは、インスタンスのassertEqual
や友人、それが機能するために厳密に依存しています。適切なレベルでのテストが確実に行われるようにするには、常にこれらのアサートを呼び出す必要があります。そのため、エラーが発生した瞬間に役立つエラーメッセージが表示されます。あなたがforループで何をしたかのような最後まで(何かが間違っていたことを教えてくれるが、何百ものうちどこが狂っているのか正確には分からない)。また、helper
メソッド - test
で始まらない限り、望むものを呼び出すことができます。なぜならフレームワークはそれを1つとして実行しようとし、ひどく失敗するからです。ですから、このコンベンションに従ってください。基本的に、テストケース内にテストを実行するためのテンプレートを用意することができます。私が行ったような入出力の束をループ内で使用することができます。
のみ(私は本当に理解していない私は、インポートたStringIOをやっていたので、私は、たStringIOのインポート少し問題を持っていたと私はStringIOをインポートたStringIOからのようにインポートするために必要な:あなたの他の質問については
なぜなら)、それがそうであるように、それは動作します。あなたは私の元のコードを見れば
まあ、私はimport io
を行なったし、その後、class StringIO(io.StringIO)
を定義することでio.StringIO
クラスをオーバーライドする方法をお見せしました。しかし、Python 2から厳密にこれをやっているので、これはあなたのために働きますが、私はPython 2が(おそらく間違いなく)5年以内にサポートされないことを考えれば、可能な限りPython 3への私の回答を対象にしようとします。あなたと同様の問題を抱えていたこの記事を読んでいる将来のユーザーを考えてみましょう。とにかく、元のfrom StringIO import StringIO
は、StringIO
モジュールのStringIO
クラスのように機能します。 from cStringIO import StringIO
は、StringIO
モジュールのC
バージョンをインポートするものとして機能するはずです。それらはすべて十分に近いインターフェイスを提供しているので、基本的には意図どおりに動作します(もちろん、これをPython 3で実行しようとするまで)。
もう一度このコードを私のコードとともに使用すると、self-contained working test scriptになります。ドキュメンテーションを見て、コードの形に従ってください。また、独自の構文を作り出すのではなく、動作することを期待してください(そして、コードが正しく機能しなかった理由は、テストコードはクラスが構築されているので、Pythonがあなたのモジュールをインポートしている間にそのすべてが実行されました。テストを実行するために必要なものもありません(つまり、クラス自体はまだ存在しません)。ただの苦しみに合わせて死ぬ)。あなたが直面している問題は本当に一般的なものですが、あなたの正確な問題を検索するための素早く簡単な名前を持たないのであれば、どこに間違っていたのか把握するのが難しいでしょうか? :)とにかく幸運と、あなたのコードをテストする努力を取って良いです。
他の方法もありますが、ここで私が見た他の質問/回答は役に立たないようですが、私はこれを願っています。参照のために他のもの:
、それはこのの全てがパイソン3.3+またはoriginal/rolling backport version on pypiで利用可能unittest.mock
を用いて行われ、それを与えることができることを繰り返すむきますこれらのライブラリは、実際に何が起こったかについて複雑な部分を隠してしまい、実際に何が起きるか(または起こる必要があるか)、またはリダイレクトが実際にどのように起こるかについての詳細を隠すことになります。必要ならば、unittest.mock.patch
を読んで、StringIO
パッチsys.stdout
セクションまで少し下に行くことができます。
本当に良い答えをいただきありがとうございます。@metatoaster私は、あなたがforループで読むためにあなたの方法を使って見つけた問題について、より多くの情報を追加しました。ありがとうございました。 –