背景
在构建测试用例集时,常常需要编写一些函数,这些函数接受基本相同的参数,仅有一个参数有所差异,并且处理模式也非常相同。可以使用Python闭包来定义模板函数,然后通过参数调节来自动化生产不同的函数。
示例
看如下代码:
def commonGenerate(startTime, endTime, field, values):
reqs = []
for val in values:
requestId = str(startTime) + "_" + str(endTime) + "_" + val
baseReq = json.loads(baseExportReqStr)
baseReq['order_search_param']['start_time'] = startTime
baseReq['order_search_param']['end_time'] = endTime
baseReq['order_search_param'][field] = [val]
baseReq['request_id'] = requestId
reqs.append(json.dumps(baseReq))
return reqs
def generateReqByState(startTime, endTime):
states = ["TOPAY", "CONFIRM", "PAID", "SENT", "SUCCESS", "CLOSE"]
return commonGenerate(startTime, endTime, 'order_state', states)
def generateReqByOrderType(startTime, endTime):
orderTypes = ["NORMAL", "GROUP", "HOTEL"]
return commonGenerate(startTime, endTime, 'order_type', orderTypes)
def generateReqByExpressType(startTime, endTime):
expressTypes = ["EXPRESS", "SELF_FETCH", "LOCAL_DELIVERY"]
return commonGenerate(startTime, endTime, 'express_type', expressTypes)
def generateReqByFeedback(startTime, endTime):
feedbacks = ["SAFE_NEW", "SAFE_FINISHED"]
return commonGenerate(startTime, endTime, 'feedback', feedbacks)
def getGenerateFuncs():
gvars = globals()
return [ gvars[var] for var in gvars if var.startswith('generateReq') ]
caseGenerateFuncs = getGenerateFuncs()
print caseGenerateFuncs
这里已经抽离出通用函数 commonGenerate ,在此基础上定义了多个 generateReqByXXX ,这些函数的模式基本相同,无非是传一个字段名及值列表,然后生成一个不一样的函数。 那么,是否可以做成可配置化呢: 只要给定一个 map[字段名,值列表], 就能自动生成这些函数 ?
使用闭包可以达到这个目标。见如下代码所示:
def commonGenerator(startTime, endTime, field, values):
def generateReqInner(startTime, endTime):
reqs = []
for val in values:
requestId = str(startTime) + "_" + str(endTime) + "_" + val
baseReq = json.loads(baseExportReqStr)
baseReq['order_search_param']['start_time'] = startTime
baseReq['order_search_param']['end_time'] = endTime
baseReq['order_search_param'][field] = [val]
baseReq['request_id'] = requestId
reqs.append(json.dumps(baseReq))
return reqs
return generateReqInner
def generateGenerators(startTime, endTime, configs):
gvars = globals()
for (field, values) in configs.iteritems():
gvars['generateReqBy' + field] = commonGenerator(startTime, endTime, field, values)
configs = {"order_state": ["TOPAY", "CONFIRM", "PAID", "SENT", "SUCCESS", "CLOSE"], \
"order_type": ["NORMAL", "GROUP", "HOTEL"], \
"express_type": ["EXPRESS", "SELF_FETCH", "LOCAL_DELIVERY"], \
"feedback": ["SAFE_NEW", "SAFE_FINISHED"]
}
def getGenerateFuncs():
gvars = globals()
return [ gvars[var] for var in gvars if var.startswith('generateReq') ]
generateGenerators(startTime, endTime, configs)
caseGenerateFuncs = getGenerateFuncs()
print caseGenerateFuncs
这里函数 commonGenerator 对 commonGenerate 做了一点改动,不再直接返回值列表,而是根据不同的参数返回一个处理不同的函数,这个函数会返回值列表; 然后 generateGenerators 根据指定配置 configs, 调用commonGenerator 来批量生产generateReqByXXX函数。妙不妙,生产函数的函数 !
原理
按维基的解释: 闭包是引用了自由变量的函数。在例子中,闭包就是 generateReqInner , 引用了传入的自由变量 field, values, 从而在 commonGenerator 调用结束之后,generateReqInner 依然存在能够被访问,且功能效果等同于 generateReqInner(startTime, endTime, field, values) 。
小结
通过Python闭包自动化生成函数,使得代码表达能力更强大了。只要做一点配置,就能自动生成相应的函数。