15

次のようなコードを単体テストしようとしています。

def main():
    parser = optparse.OptionParser(description='This tool is cool', prog='cool-tool')
    parser.add_option('--foo', action='store', help='The foo option is self-explanatory')
    options, arguments = parser.parse_args()
    if not options.foo:
        parser.error('--foo option is required')
    print "Your foo is %s." % options.foo
    return 0

if __name__ == '__main__':
   sys.exit(main())

次のようなコードを使用します。

@patch('optparse.OptionParser')
def test_main_with_missing_p4clientsdir_option(self, mock_optionparser):
    #
    # setup
    #
    optionparser_mock = Mock()
    mock_optionparser.return_value = optionparser_mock
    options_stub = Mock()
    options_stub.foo = None
    optionparser_mock.parse_args.return_value = (options_stub, sentinel.arguments)
    def parser_error_mock(message):
        self.assertEquals(message, '--foo option is required')
        sys.exit(2)
    optionparser_mock.error = parser_error_mock

    #
    # exercise & verify
    #
    self.assertEquals(sut.main(), 2)

私はMichael Foord's Mockを使用しており、nose を使用してテストを実行しています。

テストを実行すると、次のようになります。

  File "/Users/dspitzer/Programming/Python/test-optparse-error/tests/sut_tests.py", line 27, in parser_error_mock
    sys.exit(2)
SystemExit: 2

----------------------------------------------------------------------
Ran 1 test in 0.012s

FAILED (errors=1)

問題は、OptionParser.error が sys.exit(2) を実行するため、当然 main() はそれに依存することです。しかし、nose または unittest は (予想される) sys.exit(2) を検出し、テストに失敗します。

main() の parser.error() 呼び出しの下に "return 2" を追加し、parser_error_mock() から sys.exit() 呼び出しを削除することでテスト パスを作成できますが、テスト対象のコードを次のように変更するのは不快です。テストに合格できるようにします。より良い解決策はありますか?

更新: dfの答えは機能しますが、正しい呼び出しは「self.assertRaises(SystemExit, sut.main)」です。

これは、parser_error_mock() の sys.exit() にある番号が何であれ、テストが合格することを意味します。終了コードをテストする方法はありますか?

ところで、次を追加すると、テストはより堅牢になります。

self.assertEquals(optionparser_mock.method_calls, [('add_option', ('--foo',), {'action': 'store', 'help': 'The foo option is self-explanatory'}), ('parse_args', (), {})])

最後に。

更新 2 : 「self.assertRaises(SystemExit, sut.main)」を次のように置き換えることで、終了コードをテストできます。

try:
    sut.main()
except SystemExit, e:
    self.assertEquals(type(e), type(SystemExit()))
    self.assertEquals(e.code, 2)
except Exception, e:
    self.fail('unexpected exception: %s' % e)
else:
    self.fail('SystemExit exception expected')
4

4 に答える 4

12

これは代わりに機能しassertEqualsますか?

self.assertRaises(SystemExit, sut.main, 2)

これにより、例外がキャッチSystemExitされ、スクリプトが終了するのを防ぐことができます。

于 2009-01-09T00:24:15.617 に答える
1

質問の更新で述べたように、dFの回答を次のように変更する必要がありました。

self.assertRaises(SystemExit, sut.main)

...そして、終了コードをテストするためのより長いスニペットをいくつか思いつきました。

[注:私は自分の回答を受け入れましたが、この回答を削除し、彼が更新した場合はdFを受け入れます。]

于 2009-01-18T17:48:48.730 に答える
0

@raisesテスト関数に追加します。すなわち:

from nose.tools import raises

@raises(SystemExit)
@patch('optparse.OptionParser')
def test_main_with_missing_p4clientsdir_option(self, mock_optionparser):
    # Setup
    ...
    sut.main()
于 2012-12-03T17:00:16.637 に答える
0

おそらく、この質問にはいくつかの新しい情報が含まれています。

Java: System.exit() を呼び出すメソッドをテストするには?

于 2009-01-09T07:09:48.870 に答える