こんばんわ。morimotoです。
前回の数値判定の関数を一括してテストするためにテストクラスを書いてみました。 少々汚いですが暴動とかデモとか起こさないでください。。。
まずはテストクラス function_test.py
# -*- coding: utf-8 -*- class FunctionTest: def display_all(self, tests={}): for namespace in tests: print "" print "*" * 15 + (namespace + " Tests").center(30) + "*" * 15 print "" cases = tests.get(namespace, []) for case in cases: functions = case.get('functions', []) args_list = case.get('args_list', []) args_default = case.get('args_default', {}) self.display(namespace, functions, args_list, args_default) def display(self, namespace, functions, args_list, args_default={}): if functions: format, sep = self.get_format(functions[:], args_list[:]) if args_default: print " * set args default values : %s" % ",".join([" %s = %s"%(name, args_default[name],) for name in args_default]) print sep print format %1 print sep for args in args_list: print format %2 print sep print '' def get_format(self, functions, args_list): ph = lambda v: '%' + '%s'%v + 's' args_len = args_list and max([len(str(args)) for args in args_list[:]]) or 0 func_lens = [len(str(func)) for func in functions[:]] format = '| ' + ph(args_len) + ' || ' + ' | '.join([ph(fl) for fl in func_lens[:]]) + ' |' sep = '+' + '-' * (args_len + 2) + '++' + '+'.join(['-' * (fl+2) for fl in func_lens[:]]) + '+' return format, sep def execute(self, namespace, function_name, args, args_default={}): my_module = __import__(namespace) my_func = getattr(my_module, function_name) return apply(my_func, self.args_to_tuple(args), self.args_to_dict(args, args_default)) def args_to_tuple(self, args): if isinstance(args, tuple): return args if isinstance(args, list): return tuple(args) if isinstance(args, str): return tuple([args,]) return tuple([]) def args_to_dict(self, args, args_default={}): if isinstance(args, dict): args.update(args_default) return args return args_default
前回のutilities.py (try-catch でパースするのもテストしてみる)
# -*- coding: utf-8 -*- import re # Convert functions def parseInt(value, default=None): (ret,) = validates_integer_of(value) and (int(value),) or \ (validates_number_of(value) and (int(float(value)),) or (default,)) return ret def _parseInt(value, default=None): try: return int(value) except: return default # Validate functions def validates_number_of(value): return re.match(r'^(?![-+]0+$)[-+]?([1-9][0-9]*)?[0-9](\.[0-9]+)?$', '%s'%value) and True or False def validates_integer_of(value): return re.match(r'^(?![-+]0*$)[-+]?([1-9][0-9]*)?0?$', '%s'%value) and True or False def validates_float_of(value): return validates_number_of(value) and not validates_integer_of(value) or False
最後にテストするための test.py
# -*- coding: utf-8 -*- from function_test import FunctionTest from utilities import * test_values = [ "123456", "0", "-9", "+5", "+9", "0.0000", "1234.56", "-123.45", "+123.45", "-0.123", "123.00000", "+00000000", "-00000000", "+0", "-0", "ABCDEF", "1+23", "123-", "-.123", "123.", "00012", ".123", "+0000", "-0000", "+0000.22", "+", "-", ["12345"], ("12345",), {"value": "12345"}, ] test_functions = { 'utilities': [ { 'functions': ['validates_number_of', 'validates_integer_of', 'validates_float_of', ], 'args_list': test_values, }, { 'functions': ['parseInt', '_parseInt', ], 'args_list': test_values, 'args_default': { 'default': None, }, }, ] } ft = FunctionTest() ft.display_all(test_functions)
この3つのファイルを同じ階層に置いていただき、後はコンソールから
python test.py
を実行するだけです。
結果
>python test.py *************** utilities Tests *************** +--------------------++---------------------+----------------------+--------------------+ | args || validates_number_of | validates_integer_of | validates_float_of | +--------------------++---------------------+----------------------+--------------------+ | 123456 || True | True | False | | 0 || True | True | False | | -9 || True | True | False | | +5 || True | True | False | | +9 || True | True | False | | 0.0000 || True | False | True | | 1234.56 || True | False | True | | -123.45 || True | False | True | | +123.45 || True | False | True | | -0.123 || True | False | True | | 123.00000 || True | False | True | | +00000000 || False | False | False | | -00000000 || False | False | False | | +0 || False | False | False | | -0 || False | False | False | | ABCDEF || False | False | False | | 1+23 || False | False | False | | 123- || False | False | False | | -.123 || False | False | False | | 123. || False | False | False | | 00012 || False | False | False | | .123 || False | False | False | | +0000 || False | False | False | | -0000 || False | False | False | | +0000.22 || False | False | False | | + || False | False | False | | - || False | False | False | | ['12345'] || True | True | False | | ('12345',) || True | True | False | | {'value': '12345'} || True | True | False | +--------------------++---------------------+----------------------+--------------------+ * set args default values : default = None +--------------------++----------+-----------+ | args || parseInt | _parseInt | +--------------------++----------+-----------+ | 123456 || 123456 | 123456 | | 0 || 0 | 0 | | -9 || -9 | -9 | | +5 || 5 | 5 | | +9 || 9 | 9 | | 0.0000 || 0 | None | | 1234.56 || 1234 | None | | -123.45 || -123 | None | | +123.45 || 123 | None | | -0.123 || 0 | None | | 123.00000 || 123 | None | | +00000000 || None | 0 | | -00000000 || None | 0 | | +0 || None | 0 | | -0 || None | 0 | | ABCDEF || None | None | | 1+23 || None | None | | 123- || None | None | | -.123 || None | None | | 123. || None | None | | 00012 || None | 12 | | .123 || None | None | | +0000 || None | 0 | | -0000 || None | 0 | | +0000.22 || None | None | | + || None | None | | - || None | None | | ['12345'] || 12345 | 12345 | | ('12345',) || 12345 | 12345 | | {'value': '12345'} || 12345 | 12345 | +--------------------++----------+-----------+
_parseInt のほうはボロボロでした。 int()よ、しっかりしてください・・・。
以上morimotoでした。