pytestでコンソールアプリケーションのテストを書く
テスト対象のアプリケーション
コンソールアプリケーションの題材として、ここでは以下のようなアプリケーションを考えます。
次のように実装しました。
import argparse import sys def main(): parser = argparse.ArgumentParser() parser.add_argument("--name") args = parser.parse_args() template = sys.stdin.read() print(template.format(args.name)) if __name__ == "__main__": main()
実行結果は以下のようになります。
echo "hello, {}" | python3 application.py --name=world
hello, world
テスト
pytestを使ってこのアプリケーションのテストを書いてみます。ポイントとなるのはコマンドライン引数、標準入力、標準出力をどのように扱えばよいかという点です。
import io from application import main def test_main(monkeypatch): argv = ["application.py", "--name=world"] stdin = io.StringIO("hello, {}") stdout = io.StringIO() with monkeypatch.context() as m: m.setattr("sys.argv", argv) m.setattr("sys.stdin", stdin) m.setattr("sys.stdout", stdout) main() assert stdout.getvalue() == "hello, world\n"
テストが成功することを確認します。
pytest test_application.py
このテストコードについて、もう少し見ていきましょう。
コマンドライン引数
args = parser.parse_args()
この部分で内部的にsys.argv
の値を参照しています。sys.argv
はコマンドライン引数の配列です。最初の要素はスクリプトの名前になっており、その後ろに実際のコマンドライン引数が続きます。
標準入力
template = sys.stdin.read()
sys.stdin
から標準入力の文字列を取得しています。sys.stdin
はファイルオブジェクトです。
標準出力
print(template.format(args.name))
print
が実行されるとsys.stdout
に対して文字列の書き込みが発生します。sys.stdout
はsys.stdin
と同様にファイルオブジェクトです。