219

argparse ライブラリを使用する Python モジュールがあります。コード ベースのそのセクションのテストを作成するにはどうすればよいですか?

4

9 に答える 9

302

コードをリファクタリングし、解析を関数に移動する必要があります。

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')
于 2013-08-10T10:45:45.120 に答える
39

「argparse部分」は少しあいまいなので、この回答はparse_argsメソッドの一部に焦点を当てています。これは、コマンド ラインと対話し、渡されたすべての値を取得するメソッドです。基本的にparse_args、コマンドラインから実際に値を取得する必要がないように、返されるものをモックできます。このmock パッケージは、python バージョン 2.6 ~ 3.2 の pip を介してインストールできます。unittest.mockバージョン 3.3 以降の標準ライブラリの一部です。

import argparse
try:
    from unittest import mock  # python 3.3+
except ImportError:
    import mock  # python 2.6-3.2


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

Namespace たとえ渡されなくても、すべてのコマンド メソッドの引数を含める必要があります。それらの引数に の値を与えますNone。(ドキュメントを参照してください) このスタイルは、メソッドの引数ごとに異なる値が渡される場合のテストをすばやく行うのに役立ちます。テストで完全に argparse に依存しないように自分自身をモックすることを選択した場合は、実際のクラスNamespaceと同様に動作することを確認してください。Namespace

以下は、argparse ライブラリの最初のスニペットを使用した例です。

# test_mock_argparse.py
import argparse
try:
    from unittest import mock  # python 3.3+
except ImportError:
    import mock  # python 2.6-3.2


def main():
    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('integers', metavar='N', type=int, nargs='+',
                        help='an integer for the accumulator')
    parser.add_argument('--sum', dest='accumulate', action='store_const',
                        const=sum, default=max,
                        help='sum the integers (default: find the max)')

    args = parser.parse_args()
    print(args)  # NOTE: this is how you would check what the kwargs are if you're unsure
    return args.accumulate(args.integers)


@mock.patch('argparse.ArgumentParser.parse_args',
            return_value=argparse.Namespace(accumulate=sum, integers=[1,2,3]))
def test_command(mock_args):
    res = main()
    assert res == 6, "1 + 2 + 3 = 6"


if __name__ == "__main__":
    print(main())
于 2016-05-20T10:05:27.970 に答える
22

関数がデフォルトのように読み取るのではなく、引数としてmain()受け取るようにします。argvsys.argv

# 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:]))

その後、通常どおりテストできます。

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')
于 2015-04-01T22:16:28.257 に答える
10
  1. を使用して引数リストにデータを入力してsys.argv.append()から を呼び出し parse()、結果を確認して繰り返します。
  2. フラグとダンプ引数フラグを使用して、バッチ/bash ファイルから呼び出します。
  3. すべての引数解析を別のファイルに入れ、if __name__ == "__main__":呼び出し解析で結果をダンプ/評価してから、バッチ/bashファイルからこれをテストします。
于 2013-08-10T08:54:07.423 に答える