こんばんわ。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でした。