ここには2つの問題があります。関数のライブラリではなくプログラムをテストし、関数から返された値ではなく、出力するものをテストする。どちらもテストを難しくしているので、これらの問題を可能な限り解決することが最善です。
一般的な手法は、関数のライブラリを作成し、そのプログラムをその周りの薄いラッパーにすることです。これらの関数は結果を返し、プログラムだけが印刷を行います。つまり、ほとんどのコードに対して通常のユニットテスト手法を使用することができます。
ライブラリとプログラムの両方に1つのファイルを含めることができます。ここでは簡単な例をhello.py
としています。最後のビットは、それがプログラムとして実行された場合は、それがライブラリとしてインポートされた場合は、ファイルを伝えることができる方法であることを
def hello(greeting, place):
return greeting + ", " + place + "!"
def main():
print(hello("Hello", "World"))
if __name__ == '__main__':
main()
。それはimport hello
と個々の機能へのアクセスを可能にし、また、ファイルがプログラムとして実行することができます。 See this answer for more information。
次に、ほぼ通常の単体テストを書くことができます。
ここ
import hello
import unittest
import sys
from StringIO import StringIO
import subprocess
class TestHello(unittest.TestCase):
def test_hello(self):
self.assertEqual(
hello.hello("foo", "bar"),
"foo, bar!"
)
def test_main(self):
saved_stdout = sys.stdout
try:
out = StringIO()
sys.stdout = out
hello.main()
output = out.getvalue()
self.assertEqual(output, "Hello, World!\n")
finally:
sys.stdout = saved_stdout
def test_as_program(self):
self.assertEqual(
subprocess.check_output(["python", "hello.py"]),
"Hello, World!\n"
)
if __name__ == '__main__':
unittest.main()
test_hello
直接関数として、ユニットテストhello
あります。より複雑なプログラムでは、テストする機能が増えます。また、ユニットテストmain
にtest_main
があり、その出力をキャプチャするのにStringIO
を使用しています。最後に、プログラムがtest_as_program
のプログラムとして実行されるようにします。
重要なことは、データを返す関数として機能をテストし、印刷された文字列やフォーマットされた文字列としてできるだけテストしないことです。実際にプログラムをテストするまでには、main
が呼び出されていることを確認するだけです。
ユニットテストは通常、個々の関数やクラスで実行されます(通常、ファイルへの出力の書き込みやサブプロセスによる実行などは含まれません)。私は他の何かを推薦することはできませんが、チュートリアルをテストするPythonユニットを見て、それはおそらくこの質問をトピックから外すでしょう。 – byxor
それはハードドライブ上のものを変更するので、それは技術的に単体テストではありませんが、とにかくそれを行うには大丈夫です。入力と出力のためにファイルのようなオブジェクトを取る関数の中で機能を移動することによって、コードをリファクタリングすることを検討してください。通常のコードはオープンファイルハンドルと 'sys.stdout'を渡します。しかし、あなたのユニットテストコードはStringIOバッファを使用します。ターミナルに接続されたパイプの代わりにstringioに書き込むときには違いがあります。だから、これは必ずしも最善の方法ではありません。あなたは決断する必要があります。 – tdelaney
あなたはいつでも './myprog.py file.txt> result.txt'を実行し、後でツールを使ってファイルを比較することができます。 'diff result.txt expected.txt' - しかし、すべてをbash/batchスクリプトに入れても、テストとしてはあまり役に立ちません。 – furas