u++の備忘録

pythonのunittestでコマンドライン引数をテストする方法と注意点

以下の記事で作ったプログラムにおいて、コマンドライン引数をテストするケースがありました。少なくとも日本語ではまともな記事が存在しなかったので、本記事ではその手法をまとめます。

upura.hatenablog.com

テストする関数

実行時に与えたコマンドライン引数(一つ目)を取得し、'Happy birthday, ' + str(コマンドライン引数) + '!' という文字列を返します。ちなみに、sys.argv[0] には実行したファイル名が格納されています。

happy.birthday.ga/happy_birthday_ga.py at master · upura/happy.birthday.ga · GitHub

def get_objective_sentence():
    try:
        USER_NAME = sys.argv[1]
    except:
        USER_NAME = 'upura'

    objective_sentence = 'Happy birthday, ' + str(USER_NAME) + '!'
    return objective_sentence

テストコード

happy.birthday.ga/test_get_objective_sentence.py at master · upura/happy.birthday.ga · GitHub

import unittest
import sys, os
sys.path.append(os.getcwd())
from happy_birthday_ga import get_objective_sentence


class TestGetObjectiveSentence(unittest.TestCase):
    # User name is not given
    def test_success_get_default(self):
        expected = get_objective_sentence()
        actual = 'Happy birthday, upura!'
        self.assertEqual(expected, actual)

    # User name is given
    def test_success_get_user_name(self):
        sys.argv.append('Shinzo Abe')
        expected = get_objective_sentence()
        actual = 'Happy birthday, Shinzo Abe!'
        self.assertEqual(expected, actual)
        del sys.argv[1]

    # User name is given (Not a string)
    def test_success_get_not_string(self):
        sys.argv.append(111)
        expected = get_objective_sentence()
        actual = 'Happy birthday, 111!'
        self.assertEqual(expected, actual)
        del sys.argv[1]

if __name__ == "__main__":
    unittest.main()

解説

コマンドライン引数の与え方

コマンドライン引数はsys.argvにリスト形式で格納されるので、下記のように擬似的にコマンドライン引数を与えることができます。

sys.argv.append('Shinzo Abe')

コマンドライン引数のリセット

以下のように都度コマンドライン引数をリセットしないと、テストケースが複数ある際に以前のコマンドライン引数が蓄積されていってしまうので注意が必要です。

del sys.argv[1]

引数を複数与える場合は del sys.argv[1:] で削除すれば良いです。