2012-11-21 8 views
10

は、例えば、ここではプログラムのヘルプ情報は、次のとおりです。PythonのCLIプログラムの単体テスト

usage: pyconv [-h] [-f ENCODING] [-t ENCODING] [-o file_path] file_path 

Convert text file from one encoding to another. 

positional arguments: 
    file_path 

optional arguments: 
    -h, --help   show this help message and exit 
    -f ENCODING, --from ENCODING 
         Encoding of source file 
    -t ENCODING, --to ENCODING 
         Encoding you want 
    -o file_path, --output file_path 
         Output file path 

私はプログラムを変更して何かをテストしたい、ターミナルを開く必要があります。 コマンドを入力し(オプションと引数を使用)、enterと入力してエラーが発生していないかどうかを確認してください。 エラーが実際に発生した場合、私はエディタに戻ってコード を先頭から最後まで調べて、バグの位置を推測し、小さな変更を加えて、print行を書き込んでください。 端末に戻り、再度コマンドを実行してください...

再帰的に。

私の質問は、CLIプログラムでのテストを行う最良の方法は、通常のPythonスクリプトで単体テストとして簡単に とすることができますか?

答えて

3

短い答えは、あなたが、イエスです:;それぞれが失敗のタグを追加することで終わるところ)

が一度にこれらの多くを実行している場合、あなたはそれがもう少し明らかに作ることができますユニットテストを使用することができますし、必要があります。コードがうまく構成されている場合は、各コンポーネントを別々にテストするのは非常に簡単です。また、異なる引数を使用してシミュレーションを実行するには、常にsys.argvを疑似できるようにする必要があります。

0

これはPython専用ではありませんが、コマンドラインスクリプトをテストするには、さまざまな所定の入力とオプションを使用してそれらを実行し、正しい出力をファイルに格納します。次に、私が変更を加えるときにそれらをテストするために、単に新しいスクリプトを実行し、出力をdiff correct_output -にパイプするだけです。ファイルが同じ場合は何も出力しません。彼らが違うなら、それはどこに表示されます。これは、あなたがLinuxまたはOS X上にいる場合にのみ機能します。 Windowsでは、MSYSを入手する必要があります。

例:

python mycliprogram --someoption "some input" | diff correct_output -

それをさらに容易にするために、あなたはすべてのこれらのテストは、私はあなたが既に持っていると仮定あなたの「作るテスト」Makefileのターゲットに走る追加することができます。

python mycliprogram --someoption "some input" | diff correct_output - || tput setaf 1 && echo "FAILED"

1

私の質問は、CLIプログラムでテストを行う最良の方法は何ですか、通常のPythonスクリプトを使った単体テストと同じくらい簡単ですか?

唯一の違いは、スクリプトとしてPythonモジュールを実行すると、その__name__属性が'__main__'に設定されていることです。あなたは、コマンドラインからスクリプトを実行しようとするのであれば、一般的に、それはフォーム以下が必要です:スクリプトとしてまたはモジュールとして:

import sys 

# function and class definitions, etc. 
# ... 
def foo(arg): 
    pass 

def main(): 
    """Entry point to the script""" 

    # Do parsing of command line arguments and other stuff here. And then 
    # make calls to whatever functions and classes that are defined in your 
    # module. For example: 
    foo(sys.argv[1]) 


if __name__ == '__main__': 
    main() 

は今、あなたはそれを使用する方法、違いはありません。だからあなたのユニットテストコードの中であなたはちょうど foo関数をインポートすることができます、それを呼び出すと、任意のアサーションを行います。

-1

あなたは、標準のunittestのモジュールを使用することができます

# python -m unittest <test module> 

やテストフレームワークとしてnose使用を。ただ、別のディレクトリに古典unittestのファイルを作成し、実行します。

# nosetests <test modules directory> 

書き込みユニットテストが簡単です。ちょうど従いますonline manual for unittesting

1

私はプログラム全体をテストしませんが、これは良いテスト戦略ではなく、実際にエラーの実際の場所をキャッチしない可能性があります。 CLIインターフェイスは、APIのフロントエンドにすぎません。単体テストを使用してAPIをテストした後、特定の部品に変更を加えると、その変更を行うテストケースがあります。

したがって、アプリケーションを再構築して、アプリケーション自体ではなくAPIをテストするようにします。しかし、実際に完全なアプリケーションを実行し、出力が正しいことを確認する機能テストを行うことができます。

要するに、コードのテストは他のコードのテストと同じですが、変更がすべてを破らないように、組み合わせ全体ではなく個々の部分をテストする必要があります。

6

私は完全にプログラムレベルで機能的にテストするのは問題ないと思います。テストごとに1つのアスペクト/オプションをテストすることは可能です。このようにすれば、プログラムが本当に全体として機能することを確かめることができます。単体テストの作成は、通常、テストをより迅速に実行できることを意味します。通常、失敗は解釈/理解が容易です。しかし、単体テストは通常​​プログラム構造に結びついているため、内部的に物事を変更するときには、より多くのリファクタリング作業が必要になります。とにかく

は、py.testを使用して、ここでpyconv用のUTF8への変換にlatin1をテストするための小さな一例です::

# content of test_pyconv.py 

import pytest 

# we reuse a bit of pytest's own testing machinery, this should eventually come 
# from a separatedly installable pytest-cli plugin. 
pytest_plugins = ["pytester"] 

@pytest.fixture 
def run(testdir): 
    def do_run(*args): 
     args = ["pyconv"] + list(args) 
     return testdir._run(*args) 
    return do_run 

def test_pyconv_latin1_to_utf8(tmpdir, run): 
    input = tmpdir.join("example.txt") 
    content = unicode("\xc3\xa4\xc3\xb6", "latin1") 
    with input.open("wb") as f: 
     f.write(content.encode("latin1")) 
    output = tmpdir.join("example.txt.utf8") 
    result = run("-flatin1", "-tutf8", input, "-o", output) 
    assert result.ret == 0 
    with output.open("rb") as f: 
     newcontent = f.read() 
    assert content.encode("utf8") == newcontent 

pytestをインストールした後(「pytestをインストールピップ」)あなたはこのようにそれを実行することができます::

$ py.test test_pyconv.py 
=========================== test session starts ============================ 
platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev1 
collected 1 items 

test_pyconv.py . 

========================= 1 passed in 0.40 seconds ========================= 

例はpytestの固定具機構を活用しpytest自身のテストのいくつかの内部機構を再利用し、http://pytest.org/latest/fixture.htmlを参照します。詳細を忘れてしまった場合は、テストを準備して実行するのに役立つ "run"と "tmpdir"が提供されているという事実から作業できます。プレイしたい場合は、失敗したassert-statementを挿入するか、単に "assert 0"を挿入してトレースバックを見るか、 "py.test --pdb"を発行してPythonプロンプトに入ります。

+0

'run'フィクスチャでstdinとstdinを使用することはできますか? –

関連する問題