示例#1
0
 def right_click(self, xpath):
     if not self.wait_until_display(xpath):
         Logger.info("元素【{0}】不可见".format(xpath))
         return False
     element = self.driver.find_elements_by_xpath(xpath)
     ActionChains(self.driver).context_click(element).perform()
     return True
示例#2
0
 def set_checkbox(self, state, xpath):
     if not self.wait_until_display(xpath):
         Logger.info("元素【{0}】不可见".format(xpath))
         return False
     # 判断该元素是否为checkbox
     # TODO
     element = self.driver.find_elements_by_xpath(xpath)
示例#3
0
 def click(self, xpath):
     if not self.wait_until_display(xpath):
         Logger.info("元素【{0}】不可见".format(xpath))
         return False
     element = self.driver.find_element_by_xpath(xpath)
     #ActionChains(self.driver)
     element.click()
示例#4
0
 def wait_until_display(self, xpath, timeout=10000):
     # 先等待页面完成加载
     if not self.wait_until_complete():
         return False
     # 查找元素
     if not self.wait_uitl_exists(xpath):
         Logger.info("元素【{0}】不存在".format(xpath))
         return False
     # 循环
     return self.driver.find_elements_by_xpath(xpath).is_displayed()
示例#5
0
def http_code_check(resp_data, result):
    '''
    @author: eason.sun
    @resp_data: 待验证的返回值
    @return: True/False
    @summary: 校验返回数据正确
    '''
    assert resp_data in str(result)
    Logger.info("校验返回值成功")
    return True
示例#6
0
 def set_text(self, content, xpath):
     if not self.wait_until_display(xpath):
         Logger.info("元素【{0}】不可见".format(xpath))
         return False
     # 判断类型是否为输入框
     # TODO
     element = self.driver.find_elements_by_xpath(xpath)
     element.clear()
     element.send_keys(content)
     return True
示例#7
0
def revoke_api_request(params):
    """
    @author: eason.sun
    @params: API请求参数(字典类型)
    @return: 以字典的形式返回API响应数据
    """
    Logger.info("发起API请求,发送参数为:%s" % params)
    # 获取接口数据
    dict_api = Http.api_request_result(params)
    Logger.info("API接口返回数据为: %s" % dict_api)
    return dict_api
示例#8
0
def revoke_http_request(params):
    """
    @author: eason.sun
    @params: HTTP请求参数(字典类型)
    @return: 以字典的形式返回HTTP响应数据
    """
    Logger.info("发起HTTP请求,发送参数为:%s" % params)
    # 获取接口数据
    dict_http = Http.http_request_result(params)
    Logger.info("API接口返回数据为: %s" % dict_http)
    return dict_http
示例#9
0
def test_get_heartbeat():
    Logger.info('-------------------开始执行用例:【电视剧心跳:正常】--------------------')
    url = Config.HttpConfig().heartbeat.url + '?' + Config.HttpConfig(
    ).heartbeat.param1
    data = {'callback': Config.HttpConfig().heartbeat.param1}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig().heartbeat.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig().REQ_CODE)
    Logger.info('-------------------结束执行用例:【电视剧心跳:正常】--------------------')
def test_login_ByAct_shake():
    Logger.info('-------------------开始执行用例:【登陆 :正常】--------------------')
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).loginByAct.path + '?' + Config.HttpConfig_ronghe3(
    ).loginByAct.param1 + '&' + Config.HttpConfig_ronghe3().loginByAct.param2
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig_ronghe3().loginByAct.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info('-------------------结束执行用例:【登陆 :正常】--------------------')
示例#11
0
def test_get_Address_cash():
    Logger.info('-------------------开始执行用例:【获取地址:正常】--------------------')
    url = Config.HttpConfig_cashmall().URL + Config.HttpConfig_cashmall(
    ).getAddress.path + '?' + Config.HttpConfig_cashmall(
    ).getAddress.param1 + '&' + Config.HttpConfig_cashmall().getAddress.param2
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig_cashmall().getAddress.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_cashmall().REQ_CODE)
    Logger.info('-------------------结束执行用例:【获取地址:正常】--------------------')
def test_get_Share_topic():
    Logger.info('-------------------开始执行用例:【获取朋友圈分享配置:正常】--------------------')
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).getShare.path + '?' + Config.HttpConfig_ronghe3(
    ).getShare.param1 + '&' + Config.HttpConfig_ronghe3().getShare.param2
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig_ronghe3().getShare.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info('-------------------结束执行用例:【获取朋友圈分享配置:正常】--------------------')
示例#13
0
def nose_run(parser):
    Config.nose_set("verbosity", parser.verbosity)
    Config.nose_set("logging-config", Dir.log_config_path())
    # 通过关键字筛选出来的用例列表
    tests = FileHelper.tests_filter_from_dir(Dir.testcases_root_dir(),
                                             parser.select, parser.priority)
    Config.nose_set("where", Dir.testcases_root_dir())
    if len(tests):
        for i in xrange(parser.loop):
            # 生成的报表每个名称都不一样,以时间为区分
            nosexml = Dir.nose_result_path(
            ) + "wy_autotest_" + Datetime.now_str() + ".xml"
            Config.nose_set("tests", ",".join(tests))
            Config.nose_set("xunit-file", nosexml)
            Logger.info("正在第{0}/{1}次进行Nose测试".format(i + 1, parser.loop))
            Logger.info("执行Nose命令:{0}".format(Config.nose_cmd()))
            # 切换当前路径为工程根目录
            os.chdir(Dir.project_root_dir())
            os.system("nosetests")
            #发送邮件
            result_summary = Result.test_result_summary(nosexml)
            result_detail = Result.test_result_detail(nosexml)
            rev_addr_lst = [
                "*****@*****.**", "*****@*****.**",
                "*****@*****.**"
            ]
            Mail.send_email_with_attachment(
                result_summary + result_detail,
                Config.DefaultConfig().Email.Subject, nosexml, rev_addr_lst)
            Logger.info("完成第{0}/{1}次进行Nose测试".format(i + 1, parser.loop))
    else:
        Logger.info("抱歉,没有符合条件的执行测试用例!")
示例#14
0
def test_get_commentA():
    Logger.info('-------------------开始执行用例:【发表评论:正常】--------------------')
    url = Config.HttpConfig().comment.url + '?' + Config.HttpConfig(
    ).comment.param1 + '&' + Config.HttpConfig(
    ).comment.param2 + '&' + Config.HttpConfig(
    ).comment.param3 + '&' + Config.HttpConfig(
    ).comment.param4 + '&' + Config.HttpConfig(
    ).comment.param5 + '&' + Config.HttpConfig().comment.param6
    data = {'callback': "", 'channelCode': ""}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig().comment.resp,
                             common_itemconfig_result)
    #Verify.IsTrue(Common.get_http_code(url, data) == requests.codes.ok, Config.HttpConfig().REQ_CODE)
    Logger.info('-------------------结束执行用例:【发表评论:正常】--------------------')
def test_get_List():
    Logger.info('-------------------开始执行用例:【获得节目单信息:正常】--------------------')
    url = Config.HttpConfig().getListProgram.url + '?' + Config.HttpConfig(
    ).getListProgram.param1 + '&' + Config.HttpConfig().getListProgram.param2
    data = {
        'callback': Config.HttpConfig().getListProgram.param1,
        'channelCode': Config.HttpConfig().getListProgram.param2
    }
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig().getListProgram.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig().REQ_CODE)
    Logger.info('-------------------结束执行用例:【获得节目单信息:正常】--------------------')
def test_get_TopicDetail():
    Logger.info('-------------------开始执行用例:【新版新闻获取投票:正常】--------------------')
    url = Config.HttpConfig().getTopicDetail.url + '?' + Config.HttpConfig(
    ).getTopicDetail.param1 + '&' + Config.HttpConfig(
    ).getTopicDetail.param2 + '&' + Config.HttpConfig().getTopicDetail.param3
    data = {
        'callback': Config.HttpConfig().getTopicDetail.param1,
        'channelCode': Config.HttpConfig().getTopicDetail.param2
    }
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig().getTopicDetail.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig().REQ_CODE)
    Logger.info('-------------------结束执行用例:【新版新闻获取投票:正常】--------------------')
def test_save_UserResult_topic():
    Logger.info('-------------------开始执行用例:【提交猜广告结果 :正常】--------------------')
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).saveUserResult.path + '?' + Config.HttpConfig_ronghe3(
    ).saveUserResult.param1 + '&' + Config.HttpConfig_ronghe3(
    ).saveUserResult.param2 + '&' + Config.HttpConfig_ronghe3(
    ).saveUserResult.param3 + '&' + Config.HttpConfig_ronghe3(
    ).saveUserResult.param4
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig_ronghe3().saveUserResult.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info('-------------------结束执行用例:【提交猜广告结果 :正常】--------------------')
示例#18
0
def test_get_GoodsPool():
    Logger.info('-------------------开始执行用例:【获取首页商品展示:正常】--------------------')
    url = Config.HttpConfig_cashmall().URL + Config.HttpConfig_cashmall(
    ).getGoodsPool.path + '?' + Config.HttpConfig_cashmall(
    ).getGoodsPool.param1 + '&' + Config.HttpConfig_cashmall(
    ).getGoodsPool.param2
    data = {
        'callback': Config.HttpConfig_cashmall().getGoodsPool.param1,
        'channelCode': Config.HttpConfig_cashmall().getGoodsPool.param2
    }
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig_cashmall().getGoodsPool.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_cashmall().REQ_CODE)
    Logger.info('-------------------结束执行用例:【获取首页商品展示:正常】--------------------')
def test_get_ProgramTopicListByPage_topic():
    Logger.info(
        '-------------------开始执行用例:【获取某热门节目下的话题 :正常】--------------------')
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).getProgramTopicListByPage.path + '?' + Config.HttpConfig_ronghe3(
    ).getProgramTopicListByPage.param1 + '&' + Config.HttpConfig_ronghe3(
    ).getProgramTopicListByPage.param2 + '&' + Config.HttpConfig_ronghe3(
    ).getProgramTopicListByPage.param3
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(
        Config.HttpConfig_ronghe3().getProgramTopicListByPage.resp,
        common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info(
        '-------------------结束执行用例:【获取某热门节目下的话题 :正常】--------------------')
def test_get_ActUsersAnswered_topic():
    Logger.info(
        '-------------------开始执行用例:【获取已参与猜广告的用户信息 :正常】--------------------')
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).getActUsersAnswered.path + '?' + Config.HttpConfig_ronghe3(
    ).getActUsersAnswered.param1 + '&' + Config.HttpConfig_ronghe3(
    ).getActUsersAnswered.param2 + '&' + Config.HttpConfig_ronghe3(
    ).getActUsersAnswered.param3
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(
        Config.HttpConfig_ronghe3().getActUsersAnswered.resp,
        common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info(
        '-------------------结束执行用例:【获取已参与猜广告的用户信息 :正常】--------------------')
示例#21
0
def test_get_AudiNewsSize():
    Logger.info(
        '-------------------开始执行用例:【每隔十秒拉取最新审核新闻的长度:正常】--------------------')
    url = Config.HttpConfig().getAuditNewsSize.url + '?' + Config.HttpConfig(
    ).getAuditNewsSize.param1 + '&' + Config.HttpConfig(
    ).getAuditNewsSize.param2
    data = {
        'callback': Config.HttpConfig().getAuditNewsSize.param1,
        'channelCode': Config.HttpConfig().getAuditNewsSize.param2
    }
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig().getAuditNewsSize.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig().REQ_CODE)
    Logger.info(
        '-------------------结束执行用例:【每隔十秒拉取最新审核新闻的长度:正常】--------------------')
def test_get_ProgramStatisticsNum_topic():
    Logger.info(
        '-------------------开始执行用例:【获取热门电视下的话题数量和评论数量 :正常】--------------------'
    )
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).getProgramStatisticsNum.path + '?' + Config.HttpConfig_ronghe3(
    ).getProgramStatisticsNum.param1 + '&' + Config.HttpConfig_ronghe3(
    ).getProgramStatisticsNum.param2
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(
        Config.HttpConfig_ronghe3().getProgramStatisticsNum.resp,
        common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info(
        '-------------------结束执行用例:【获取热门电视下的话题数量和评论数量 :正常】--------------------'
    )
示例#23
0
def test_get_appealOrder():
    Logger.info('-------------------开始执行用例:【申请售后:正常】--------------------')
    url = Config.HttpConfig_cashmall().URL + Config.HttpConfig_cashmall(
    ).appealOrder.path + '?' + Config.HttpConfig_cashmall(
    ).appealOrder.param1 + '&' + Config.HttpConfig_cashmall(
    ).appealOrder.param2 + '&' + Config.HttpConfig_cashmall(
    ).appealOrder.param3 + '&' + Config.HttpConfig_cashmall(
    ).appealOrder.param4 + '&' + Config.HttpConfig_cashmall(
    ).appealOrder.param5 + '&' + Config.HttpConfig_cashmall(
    ).appealOrder.param6 + '&' + Config.HttpConfig_cashmall(
    ).appealOrder.param7
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig_cashmall().appealOrder.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_cashmall().REQ_CODE)
    Logger.info('-------------------结束执行用例:【申请售后:正常】--------------------')
def test_get_ChannelConfig_shake():
    Logger.info(
        '-------------------开始执行用例:【获取频道信息(进入按钮图片enterBtnImg、互动背景图actBgImg、摇宝图片yaoBaoImg) :正常】--------------------'
    )
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).getChannelConfigShake.path + '?' + Config.HttpConfig_ronghe3(
    ).getChannelConfigShake.param1 + '&' + Config.HttpConfig_ronghe3(
    ).getChannelConfigShake.param2 + '&' + Config.HttpConfig_ronghe3(
    ).getChannelConfigShake.param3
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(
        Config.HttpConfig_ronghe3().getChannelConfigShake.resp,
        common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info(
        '-------------------结束执行用例:【获取频道信息(进入按钮图片enterBtnImg、互动背景图actBgImg、摇宝图片yaoBaoImg) :正常】--------------------'
    )
def test_get_ChannelConfigByType_topic():
    Logger.info(
        '-------------------开始执行用例:【显示设置(是否显示理财、电影、精彩推荐等):正常】--------------------'
    )
    url = Config.HttpConfig_ronghe3().URL + Config.HttpConfig_ronghe3(
    ).getChannelConfigByType.path + '?' + Config.HttpConfig_ronghe3(
    ).getChannelConfigByType.param1 + '&' + Config.HttpConfig_ronghe3(
    ).getChannelConfigByType.param2 + '&' + Config.HttpConfig_ronghe3(
    ).getChannelConfigByType.param3
    data = {}
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(
        Config.HttpConfig_ronghe3().getChannelConfigByType.resp,
        common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_ronghe3().REQ_CODE)
    Logger.info(
        '-------------------结束执行用例:【显示设置(是否显示理财、电影、精彩推荐等):正常】--------------------'
    )
示例#26
0
 def navigate(self, n_url):
     Logger.info("浏览器正在跳转页面:%s" % n_url)
     self.driver.get(n_url)
     if not self.wait_until_complete():
         return False
     self.init_time = self.timing(Config.WebConfig().Timing.InitTime)
     self.redirect_time = self.timing(
         Config.WebConfig().Timing.RedirectTime)
     self.appcache_time = self.timing(
         Config.WebConfig().Timing.AppCacheTime)
     self.dns_time = self.timing(Config.WebConfig().Timing.DnsTime)
     self.tcp_time = self.timing(Config.WebConfig().Timing.TcpTime)
     self.request_time = self.timing(Config.WebConfig().Timing.RequestTime)
     self.response_time = self.timing(
         Config.WebConfig().Timing.ResponseTime)
     self.processing_time = self.timing(
         Config.WebConfig().Timing.ProcessingTime)
     self.onload_time = self.timing(Config.WebConfig().Timing.OnloadTime)
     self.total_time = self.timing(Config.WebConfig().Timing.TotalTime)
     self.timing_detail()
     return True
示例#27
0
def test_get_ProductList():
    Logger.info('-------------------开始执行用例:【获取全部商品:正常】--------------------')
    url = Config.HttpConfig_cashmall().URL + Config.HttpConfig_cashmall(
    ).getProductList.path + '?' + Config.HttpConfig_cashmall(
    ).getProductList.param1 + '&' + Config.HttpConfig_cashmall(
    ).getProductList.param2 + '&' + Config.HttpConfig_cashmall(
    ).getProductList.param3 + '&' + Config.HttpConfig_cashmall(
    ).getProductList.param4 + '&' + Config.HttpConfig_cashmall(
    ).getProductList.param5 + '&' + Config.HttpConfig_cashmall(
    ).getProductList.param6 + '&' + Config.HttpConfig_cashmall(
    ).getProductList.param7
    data = {
        'callback': Config.HttpConfig_cashmall().getProductList.param1,
        'channelCode': Config.HttpConfig_cashmall().getProductList.param2
    }
    common_itemconfig_result = Common.revoke_get_request(url, data)
    #Response.http_code_check(Config.HttpConfig_cashmall().getProductList.resp, common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig_cashmall().REQ_CODE)
    Logger.info('-------------------结束执行用例:【获取全部商品:正常】--------------------')
def test_get_saveTipoff():
    Logger.info('-------------------开始执行用例:【提交爆料:正常】--------------------')
    url = Config.HttpConfig().saveTipoff.url + '?' + Config.HttpConfig(
    ).saveTipoff.param1 + '&' + Config.HttpConfig(
    ).saveTipoff.param2 + '&' + Config.HttpConfig(
    ).saveTipoff.param3 + '&' + Config.HttpConfig(
    ).saveTipoff.param4 + '&' + Config.HttpConfig(
    ).saveTipoff.param5 + '&' + Config.HttpConfig(
    ).saveTipoff.param6 + '&' + Config.HttpConfig(
    ).saveTipoff.param7 + '&' + Config.HttpConfig(
    ).saveTipoff.param8 + '&' + Config.HttpConfig().saveTipoff.param9
    data = {
        'callback': Config.HttpConfig().saveTipoff.param1,
        'channelCode': Config.HttpConfig().saveTipoff.param2
    }
    common_itemconfig_result = Common.revoke_get_request(url, data)
    Response.http_code_check(Config.HttpConfig().saveTipoff.resp,
                             common_itemconfig_result)
    Verify.IsTrue(
        Common.get_http_code(url, data) == requests.codes.ok,
        Config.HttpConfig().REQ_CODE)
    Logger.info('-------------------结束执行用例:【提交爆料:正常】--------------------')
示例#29
0
def api_response_result_null(resp_dict):
    """
    @author: eason.sun
    @resp_dict: 待比对的字典集和
    @return: 对API返回的数据进行空值校验 True/False
    @summary: 比较字典内容是否为空,以下为接口返回数据:version/action/errCode/allRows/data
    """
    if not resp_dict.has_key(Config.ApiConfig().ResponseStruct.VersionKey):
        return False
    Logger.info("API接口数据中有版本信息")
    if not resp_dict.has_key(Config.ApiConfig().ResponseStruct.ActionKey):
        return False
    Logger.info("API接口数据中有Action信息")
    if not resp_dict.has_key(Config.ApiConfig().ResponseStruct.ErrorCodeKey):
        return False
    Logger.info("API接口数据中有错误码信息")
    if not resp_dict.has_key(Config.ApiConfig().ResponseStruct.AllRowsKey):
        return False
    Logger.info("API接口数据中有行数信息")
    if not resp_dict.has_key(Config.ApiConfig().ResponseStruct.DataKey):
        return False
    Logger.info("API接口数据中有数据信息")
    return True
示例#30
0
def exec_time(func, *args, **kwargs):
    Logger.info("函数 %s 开始执行" % func.__name__)
    start_time = time.time()
    func(*args, **kwargs)

    end_time = time.time()
    Logger.info("函数 %s 执行完毕" % func.__name__)

    taken = end_time - start_time
    Logger.info("函数 %s 执行耗时:@%.3fs" % (func.__name__, taken))
    return taken