2013-08-10 6 views
79

私はargparseライブラリを使用するPythonモジュールを持っています。コードベースのそのセクションのテストを書くにはどうしたらいいですか?Pythonモジュールのargparse部分のテストを書く方法は?

+6

私はジャークのように出くわすことなくこれをどう言うべきか分かりませんが、「テスト」という言葉なしでも何かにリンクすると私を助けますか? – pydanny

+0

argparseはコマンドラインインターフェイスです。コマンドラインからアプリケーションを呼び出すためのテストを書いてください。 – Homer6

答えて

100

あなたはあなたのコードをリファクタリングし、関数に構文解析を移動する必要があります:

def parse_args(args): 
    parser = argparse.ArgumentParser(...) 
    parser.add_argument... 
    # ...Create your parser as you like... 
    return parser.parse_args(args) 

次に、あなたのmain機能であなただけでそれを呼び出す必要があります:

parser = parse_args(sys.argv[1:]) 

(最初の要素スクリプトの名前を表すsys.argvの名前は、CLI操作中に追加のスイッチとして送信されないように削除されます)。

あなたのテストでは

、あなたは、あなたがして、それをテストしたい引数のどんなリストでパーサ関数を呼び出すことができます。

def test_parser(self): 
    parser = parse_args(['-l', '-m']) 
    self.assertTrue(parser.long) 
    # ...and so on. 

あなたがちょうどテストするアプリケーションのコードを実行する必要は決してないだろう。この方法パーサ。

変更および/または後に、アプリケーションのあなたのパーサーにオプションを追加し、その後、ファクトリメソッドを作成する必要がある場合:あなたがしたい場合は、後でそれを操作することができ、かつテストは次のようになり

def create_parser(): 
    parser = argparse.ArgumentParser(...) 
    parser.add_argument... 
    # ...Create your parser as you like... 
    return parser 

を:

class ParserTest(unittest.TestCase): 
    def setUp(self): 
     self.parser = create_parser() 

    def test_something(self): 
     parsed = self.parser.parse_args(['--something', 'test']) 
     self.assertEqual(parsed.something, 'test') 
+2

あなたの答えをありがとう。特定の引数が渡されなかった場合のエラーのテスト方法を教えてください。 –

+2

@PratikKhadloya引数が必須で、渡されない場合、argparseは例外を送出します。 –

+0

そうですが、例外のメッセージもテストしようとしています。例外オブジェクトでメッセージを保持できません。 https://gist.github.com/tispratik/aebff28b8c5afd7bee59 –

4
  1. は、結果を確認し、繰り返し、sys.argv.append()を使用して引数リストを移入し、その後 parse()を呼び出します。
  2. フラグとダンプ引数フラグを使用してバッチ/ bashファイルから呼び出します。
  3. 引数の解析をすべて別のファイルに入れて、if __name__ == "__main__":コール解析と結果のダンプ/評価を行い、次にこれをバッチ/ bashファイルからテストします。
3

パーサをテストする簡単な方法は次のとおりです。

parser = ... 
parser.add_argument('-a',type=int) 
... 
argv = '-a 1 foo'.split() # or ['-a','1','foo'] 
args = parser.parse_args(argv) 
assert(args.a == 1) 
... 

もう一つの方法はにあります

# mymodule.py 
import argparse 
import sys 


def main(args): 
    parser = argparse.ArgumentParser() 
    parser.add_argument('-a') 
    process(**vars(parser.parse_args(args))) 
    return 0 


def process(a=None): 
    pass 

if __name__ == "__main__": 
    sys.exit(main(sys.argv[1:])) 

次にあなたがテストすることができます:あなたのmain()機能はむしろ​​させるよりも、引数としてargvを取る作るsys.argvを変更して、テスト​​の例の多くはlib/test/test_argparse.py

4

でありargs = parser.parse_args()

を呼び出します通常は。

import mock 

from mymodule import main 


@mock.patch('mymodule.process') 
def test_main(process): 
    main([]) 
    process.assert_call_once_with(a=None) 


@mock.patch('foo.process') 
def test_main_a(process): 
    main(['-a', '1']) 
    process.assert_call_once_with(a='1') 
-1

私は最も簡単な方法は、私にとっては少なくとも、sys.argvのを確認することだけであることを見出した[0]ので、Pythonがpython -m unittestとして実行し、それが事実であれば何を解析していなかったかどうかを確認します。

import sys 
import argparse 

parser = argparse.ArgumentParser() 

parser.add_argument('--outdir', help='Directory to output to', \ 
    default='out') 
parser.add_argument('--file', help='Input file', \ 
    default='section') 
parser.add_argument('--word', help='Word to look up') 

if sys.argv[0] == 'python -m unittest': 
    args = parser.parse_args([]) 
else: 
    args = parser.parse_args() 
6

「argparseの部分は、」少し曖昧であるので、この答えは一つの部分に焦点を当て:parse_args方法。これは、コマンドラインと対話し、渡されたすべての値を取得するメソッドです。基本的には、parse_argsが返すものを気にして、実際にコマンドラインから値を取得する必要はありません。

import argparse 
import mock 


@mock.patch('argparse.ArgumentParser.parse_args', 
      return_value=argparse.Namespace(kwarg1=value, kwarg2=value)) 
def test_command(mock_args): 
    pass 

あなたは、彼らが渡されていない場合でも、Namespaceにすべてのコマンド方式の引数を含める必要があります。それらの引数にNoneの値を与えます。 (docsを参照)このスタイルは、メソッド引数ごとに異なる値が渡される場合のテストを素早く行うのに便利です。 Namespace自体を模擬してテストでのargparse非依存性を選択する場合は、実際のNamespaceクラスと同様に動作することを確認してください。

+0

しかし、あなたのunittestコードは 'argparse'と' Namespace'クラスにも依存しています。 'Namespace'をモックする必要があります。 –

+0

@DrunkenMasterはスニークトーンのために謝罪します。私は説明と可能な使用法で私の答えを更新しました。私はここでも学んでいます。そうすれば、戻り値を嘲笑することが有益なケースを提供することができますか? (または、少なくとも戻り値を嘲笑しない*有害な場合) –

関連する問題