def assert_actualTime_in_timeErrorRange(self, actual_time, offset_sec=None): ''' 功能:实际时间是否在当前时间允许的误差范围内 :param actual_time: 待校验的时间,其时间格式为:%Y-%m-%d %H:%M:%S :param offset_sec: 时间误差偏移量 :return: ''' # 默认参数定义 if not offset_sec: offset_sec = 5 # time_format = "%Y-%m-%d %H:%M:%S" # 获取到实际的时间戳 actual_timestamp = TimeHelper.get_timestamp_from_time(actual_time) # 获取期望的时间戳范围 floor_expect_timestamp = actual_timestamp - offset_sec ceil_expect_timestamp = actual_timestamp + offset_sec with allure.step('[断言校验]实际时间在期望时间区间范围内,误差偏移量是 {}秒'.format(offset_sec)): AllureHelper.attachText("", "实际时间:{}".format(actual_time)) AllureHelper.attachText( "", "期望时间区间:{}--{}".format( TimeHelper.get_time_from_timestamp(floor_expect_timestamp), TimeHelper.get_time_from_timestamp(ceil_expect_timestamp))) assert actual_timestamp >= floor_expect_timestamp and actual_timestamp <= ceil_expect_timestamp
def get_alarmId(timestamp=None): if timestamp is None: timestamp = timestamp tmp_time = TimeHelper.get_time_from_timestamp(timestamp) timestamp = TimeHelper.get_timestamp_from_time(assigned_time=tmp_time) part_1 = TimeHelper.get_time_from_timestamp(timestamp=timestamp, time_format="%Y-%m-%d_%H-%M-%S") part_2 = StringHelper.random_digit(100,999) part_3 = StringHelper.random_digit(1000,9999) part_4 = StringHelper.random_digit(0,9) return "{}_{}_{}_{}".format(part_1, part_2, part_3, part_4)
def test_正测_成功查询设备列表_复合查询_设备编码和注册时间(self, 已注册_IOT设备): with allure.step('准备用例入参'): pageNo = 1 pageSize = 20 areaCodesList = None deviceStatus = None deviceCodeOrBar = 已注册_IOT设备["deviceCode"] deviceType = None manufacturerType = None lensType = None hardwareVersion = None startDateTime = TimeHelper.get_custom_time(-3600) endDateTime = TimeHelper.get_custom_time(3600) with allure.step('接口请求'): res_info = api_admin.bns_iotDevice_list( pageNo=pageNo, pageSize=pageSize, areaCodesList=areaCodesList, deviceStatus=deviceStatus, deviceCodeOrBar=deviceCodeOrBar, deviceType=deviceType, manufacturerType=manufacturerType, lensType=lensType, hardwareVersion=hardwareVersion, startDateTime=startDateTime, endDateTime=endDateTime, ) with allure.step('校验:接口响应信息'): with allure.step('校验:接口状态码'): actual_code = JsonHelper.parseJson_by_objectpath(res_info, "$.response_data.code") expect_code = 0 self.assert_actual_equal_expect("接口业务码", actual_code, expect_code) with allure.step('校验:接口返回的业务信息条数'): expect_count = 1 actual_count = JsonHelper.parseJson_by_objectpath(res_info, "$.response_data.data.total") self.assert_actual_equal_expect("校验筛选查询后列表中内容条数", actual_count, expect_count) with allure.step('校验:接口返回的业务信息内容'): expect_content = 已注册_IOT设备["deviceCode"] actual_content = JsonHelper.parseJson_by_objectpath(res_info, "$.response_data.data.list") self.assert_actual_contain_expect("校验筛选查询后列表应包含内容", actual_content, expect_content)
def _content_bns(self): """ :return: 业务api的模板代码内容 """ return """# -*- coding: utf-8 -*- # @Time : {0} from base.decorators import allure_attach class BnsApi(BusinessApi): def __init__(self, username=None, password=None): super().__init__(username=username,password=password) self._config_{1} = self.base_yaml_info( curr_file=__file__, module_key=__name__.split(".")[-2] ) @allure_attach("{5}") def bns_{1}_{2}(self, headers=None, {3}): # TODO: 请完成函数注释!!! api_info = self._config_{1}["{2}"] http_url = api_info["url"] http_port = api_info.get("port") http_method = api_info["method"] http_contentType = api_info["contentType"] http_data = api_info["Report_Data"] # 请求入参 Report_Data = {{ {4} }} Report_Data = self.base_filter_data(Report_Data) # 请求地址 response = self.business_request( # TODO: 请确认url是否需要变化!!! request_url="{{}}{{}}".format(self.base_url(http_port), http_url), request_method=http_method, request_type=http_contentType, request_data=Report_Data, headers=headers ) return response """.format( TimeHelper.get_time_from_timestamp(), self.module_key, self.func_key, self._parseYaml_params_eqNone(self.http_params), self._parseYaml_params_request(self.http_params), self.http_desc )
def simulate_device_uploadPic(self, img_time=None, score=None, img_path=None, body_img_path=None, userStatus=None, capAngle=None): if img_time is None: img_time = TimeHelper.get_time(t=TimeHelper.get_time_from_timestamp(), offset=10) if score is None: score = str(random.randint(80, 190) / 100) if img_path is None: img_path = gen_bnsData.get_face_picture(index=1) face_frame = ImageHelper.pic_to_bytes(img_path) if body_img_path is None: body_frame = face_frame else: body_frame = ImageHelper.pic_to_bytes(body_img_path) if userStatus is None: userStatus = 2 # 默认进店 if capAngle is None: capAngle = 0 # 默认正脸 alarmId = gen_bnsData.get_alarmId(timestamp=TimeHelper.get_timestamp_from_time(assigned_time=img_time)) pb_login_msg = pb_business.upload_v4_data(self.aes_key, img_time, face_frame, body_frame, float(score), userStatus, capAngle, alarmId) msg_aes_len = len(pb_login_msg) format = '>BIHI%ds' % (msg_aes_len) send_msg = struct.pack(format, int('0x1A', 16), msg_aes_len, func_num_map.DankiV4ReportData, 0, pb_login_msg) # 定义函数需要返回的信息 info_dict = dict() info_dict.setdefault('img_time', img_time) info_dict.setdefault('score', score) info_dict.setdefault('alarmId', alarmId) info_dict.setdefault('userStatus', userStatus) info_dict.setdefault('capAngle', capAngle) # info_dict.setdefault('face_frame', face_frame) self.checkLoginInfo() self.send_message(send_msg) self.log.log_info("设备上报图片信息:{}".format(info_dict)) self.checkReplyInfo() AllureHelper.attachJson(info_dict, "设备上报的信息") AllureHelper.attachPic(face_frame, "设备上报的图片") return info_dict
def __setting_response_format(self, response): response_code = response.status_code self.info['response_code'] = response_code self.info['response_time'] = response.elapsed.total_seconds() self.info['local_time'] = TimeHelper.get_time_from_timestamp() self.info['response_data'] = response.text self.info['response_header'] = dict(response.headers) # 进行http的状态码的检测 ''' 200 请求成功 401 接口未授权 404 接口请求地址不存在 500 接口服务器内部错误 502 请求失败:接口服务器运行错误:服务是否启动,端口是否可用,网络能否ping通 ''' # if response_code == 200 or 201: if response_code == 200: response_ContentType = response.headers.get("Content-Type") if "application/json" in response_ContentType: try: self.info['response_data'] = response.json() except Exception: self.log.log_error(self.info) raise exceptions.HttpResponseException( "请求类型是json,但接口返回内容却不是json格式") elif "image" in response_ContentType: self.info['response_data'] = response.content else: self.log.log_warning("响应内容类型不是json也不是image,是其他类型:{}".format( response_ContentType)) self.info['response_data'] = response.text if self.verbose: self.log.log_info("接口响应信息:{}".format( self.info['response_data'])) return self.info self.log.log_warning("请求请求地址:{}".format(self.info['request_addrPath'])) self.log.log_warning("请求响应的http状态码:{}".format(response_code)) try: self.info['response_data'] = response.json() except: self.info['response_data'] = response.text return self.info
def _content_module(self): """ :return: 接口模块级用例的模板代码内容 """ return """# -*- coding: utf-8 -*- # @Time : {0} import pytest import allure from case import BaseCase from bns.facepass.api import Api # 业务api的调用入口 from base.helper import JsonHelper # json信息提取 import testdata # 可随机化的简单参数 from case import utils # 可复用的用例步骤 #### tmp use #### api_admin = Api(username=None,password=None) #### tmp use #### @pytest.fixture(scope="function") def depend_{1}Info(): with allure.step("前置条件: 添加xxx"): # 调用scn api,期望返回一个信息字典info # info = api_admin.scn_device_add_snapCamera() # 从信息字典中取出唯一性信息, 如id信息 # {1}Id = info["{1}Id"] yield info with allure.step("清理前置条件: 删除xxx"): # 从bns api中调用模块的delete方法 # api_admin.bns_device_delete(deviceId=deviceId) @allure.feature("xxx标签") @allure.story("{4}") class Test{2}{3}(BaseCase): @allure.severity(allure.severity_level.NORMAL) def test_正测_成功xxx_xxx(self): with allure.step('准备用例入参'): {5} with allure.step('接口请求'): res_info = api_admin.bns_{1}_{7}( {6} ) with allure.step('校验:接口响应信息'): with allure.step('校验:接口状态码'): actual_code = JsonHelper.parseJson_by_objectpath(res_info, "$.response_data.code") expect_code = 0 self.assert_actual_equal_expect("接口业务码", actual_code, expect_code) with allure.step('校验:关联业务'): # 每个关联业务写成一个step pass with allure.step('清理用例'): pass """.format( TimeHelper.get_time_from_timestamp(), self.module_key, self.module_key.capitalize(), self.func_key.capitalize(), self.http_desc, self._parseYaml_params_parameterize(self.http_params, self.module_key), self._parseYaml_params_eqSelf(self.http_params), self.func_key)
def _content_field(self): """ :return: 接口字段级用例的模板代码内容 """ return """# -*- coding: utf-8 -*- # @Time : {0} import sys import allure import pytest from base.helper import JsonHelper from case import BaseCase _testData_list = BaseCase().csv_info(curr_file=__file__) # 获取api操作对象, 默认权限为平台管理员 api_object_admin = BnsApi() class Test{5}(BaseCase): @pytest.mark.parametrize("test_data", _testData_list) def test_field_{1}_{2}(self, test_data): first_layer = test_data["first_layer"] sencod_layer = test_data["sencod_layer"] third_layer = test_data["third_layer"] if first_layer: allure.dynamic.epic(first_layer) if sencod_layer: allure.dynamic.feature(sencod_layer) if third_layer: allure.dynamic.story(third_layer) module_key = sys._getframe().f_code.co_name.split("_")[2] test_data = self.parse_csv_param(test_data, module_key) {4} with allure.step("步骤: 请求接口"): res_json = api_object_admin.bns_{1}_{2}( {3} ) with allure.step("步骤: 提取接口的业务状态码"): actual_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_data.code") with allure.step("校验: 业务状态码是否正确"): self.assert_actual_equal_expect("业务状态码", actual_code, test_data["expect_code"]) if test_data["expect_msg"]: with allure.step("步骤: 提取接口的提示信息"): actual_msg = JsonHelper.parseJson_by_objectpath(res_json, "$.response_data.message") with allure.step("校验: 提示信息是否正确"): self.assert_actual_contain_expect("提示信息", actual_msg, test_data["expect_msg"]) if test_data["clean_data"]: with allure.step("步骤: 数据清理操作"): # TODO: 调用删除接口 pass generator_objs_list = test_data.get("generator_objs_list") if generator_objs_list: for generator_obj in generator_objs_list: try: generator_obj.__next__() except StopIteration: pass """.format(TimeHelper.get_time_from_timestamp(), self.module_key, self.func_key, self._parseYaml_params_eqSelf(self.http_params), self._parseYaml_params_testdata(self.http_params), self.module_key.capitalize())
1. scn api 的封装 2. 模块用例和场景用例 """ import random import datetime from base.helper import StringHelper from base.helper import JsonHelper from testdata.addr import node_addr from base.helper import TimeHelper from base.helper import FileHelper import os import string now_date = TimeHelper.get_time_from_timestamp()[:10] ################# 声明一些重要的路径或资源路径 ################# # 项目根目录 __project_rootdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 上报图片的目录 img1_dir = __project_rootdir + os.sep + 'testdata' + os.sep + 'upload_pics_1' + os.sep # 上报像素图片的目录 pixel_img_dir = __project_rootdir + os.sep + 'testdata' + os.sep + 'upload_pics_facePixel' + os.sep def random_queryMenu_id(): return random.choice(range(0, 20)) def random_publicDevice_lensType():
def _content_scn(self): """ :return: 场景api的模板代码内容 """ if "add" in self.func_key: return """# -*- coding: utf-8 -*- # @Time : {0} from base.decorators import api_retry from base.exceptions import DefinedBusinessException, UndefinedBusinessException from base.helper import JsonHelper from testdata import gen_bnsData class ScnApi(BnsApi): def __init__(self, username=None, password=None): super().__init__(username=username, password=password) @api_retry() def scn_{1}_{2}(self, headers=None, {3}, res_accurate=False, business_exception=False): # TODO: 请确定参数并完成参数注释 # 参数化 {6} # 发送业务请求 res_json = self.bns_{1}_{2}(headers=headers,\n\t\t\t\t\t\t\t\t\t\t{4}) # 定义一个http状态码的白名单, 如果状态码不在白名单中,则直接返回 white_list = [200, 201] # 获取当前请求的http状态码 http_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_code") # 如果请求返回的状态码不是期望的http状态码, 则直接返回该状态码 if http_code not in white_list: return res_json # 提取业务码 actually_business_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_data.code") # 异常码集合 exception_list = [ # 400004, # 设备类型不合法 ] # 正常业务状态码下, 函数的返回信息 if actually_business_code == 0: # 解析返回信息或调用自定义函数 # 精确返回的内容 if res_accurate: pass # return deviceCode # 全部信息返回 info_dict = dict() # TODO: 请确认,是否需要接收其他必要信息, 如添加后产生的唯一性标识信息 {7} return info_dict if info_dict else JsonHelper.parseJson_by_objectpath(res_json, "$.response_data") # 异常业务状态码下(已知异常), 函数的返回信息 elif actually_business_code in exception_list: if business_exception: raise DefinedBusinessException("接口已知业务异常:{5}") return JsonHelper.parseJson_by_objectpath(res_json, "$.response_data") # 异常业务状态码下(未知异常), 函数的返回信息 else: raise UndefinedBusinessException("接口未知业务异常:{5}") """.format( TimeHelper.get_time_from_timestamp(), self.module_key, self.func_key, self._parseYaml_params_eqNone(self.http_params), self._parseYaml_params_eqSelf(self.http_params), self.http_desc, self._parseYaml_params_parameterize(self.http_params, self.module_key), self._parseYaml_params_responseApiDict(self.http_params)) elif "edit" in self.func_key: return """# -*- coding: utf-8 -*- # @Time : {0} from base.decorators import retry_common_api from base.exceptions import DefinedBusinessException, UndefinedBusinessException from base.helper import JsonHelper class ScnApi(BnsApi): def __init__(self, username=None, password=None): super().__init__(username=username, password=password) @retry_common_api() def scn_{1}_{2}(self, headers=None, {3}, res_accurate=False, business_exception=False): # TODO: 请确定参数并完成参数注释 # 参数化 # TODO: 参数化--获取详情信息 # detail_info = {{}} # TODO: 参数化--确认不可编辑参数 # TODO: 参数化--确认可编辑参数 # deviceName = detail_info.get("name") # if edit_deviceName is not None: deviceName = edit_deviceName # 发送业务请求 res_json = self.bns_{1}_{2}(headers=headers,\n\t\t\t\t\t\t\t\t\t\t{4}) # 定义一个http状态码的白名单, 如果状态码不在白名单中,则直接返回 white_list = [200, 201] # 获取当前请求的http状态码 http_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_code") # 如果请求返回的状态码不是期望的http状态码, 则直接返回该状态码 if http_code not in white_list: return res_json # 提取业务码 actually_business_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_data.code") # 异常码集合 exception_list = [ # 400004, # 设备类型不合法 ] # 正常业务状态码下, 函数的返回信息 if actually_business_code == 0: # 解析返回信息或调用自定义函数 # 精确返回的内容 if res_accurate: pass # return deviceCode # 全部信息返回 info_dict = dict() # TODO: 参考对应的add接口信息 # if deviceType: info_dict.setdefault('deviceType', deviceType) return info_dict if info_dict else JsonHelper.parseJson_by_objectpath(res_json, "$.response_data") # 异常业务状态码下(已知异常), 函数的返回信息 elif actually_business_code in exception_list: if business_exception: raise DefinedBusinessException("接口已知业务异常:{5}") return JsonHelper.parseJson_by_objectpath(res_json, "$.response_data") # 异常业务状态码下(未知异常), 函数的返回信息 else: raise UndefinedBusinessException("接口未知业务异常:{5}") """.format( TimeHelper.get_time_from_timestamp(), self.module_key, self.func_key, self._parseYaml_params_addPrefixEdit_eqNone(self.http_params), self._parseYaml_params_eqSelf(self.http_params), self.http_desc) else: return """# -*- coding: utf-8 -*- # @Time : {0} from base.decorators import retry_common_api from base.exceptions import DefinedBusinessException, UndefinedBusinessException from base.helper import JsonHelper class ScnApi(BnsApi): def __init__(self, username=None, password=None): super().__init__(username=username, password=password) def scn_{1}_{2}(self, headers=None, {3}, res_accurate=False, business_exception=False): # TODO: 请确定参数并完成参数注释 # 参数化 # if func_param is None: func_param = gen_bnsData.xxx() # 发送业务请求 res_json = self.bns_{1}_{2}(headers=headers,\n\t\t\t\t\t\t\t\t\t\t{4}) # 定义一个http状态码的白名单, 如果状态码不在白名单中,则直接返回 white_list = [200, 201] # 获取当前请求的http状态码 http_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_code") # 如果请求返回的状态码不是期望的http状态码, 则直接返回该状态码 if http_code not in white_list: return res_json # 提取业务码 actually_business_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_data.code") # 异常码集合 exception_list = [ # 400004, # 设备类型不合法 ] # 正常业务状态码下, 函数的返回信息 if actually_business_code == 0: # 解析返回信息或调用自定义函数 # 精确返回的内容 if res_accurate: pass # return deviceCode # 全部信息返回 info_dict = dict() return info_dict if info_dict else JsonHelper.parseJson_by_objectpath(res_json, "$.response_data") # 异常业务状态码下(已知异常), 函数的返回信息 elif actually_business_code in exception_list: if business_exception: raise DefinedBusinessException("接口已知业务异常:{5}") return JsonHelper.parseJson_by_objectpath(res_json, "$.response_data") # 异常业务状态码下(未知异常), 函数的返回信息 else: raise UndefinedBusinessException("接口未知业务异常:{5}") """.format(TimeHelper.get_time_from_timestamp(), self.module_key, self.func_key, self._parseYaml_params_eqNone(self.http_params), self._parseYaml_params_eqSelf(self.http_params), self.http_desc)
def scn_device_auth(self, deviceCode, data=None, headers=None, res_accurate=False, business_exception=False): ''' :param headers: :param deviceCode: 设备编码 :param data: 数据加密 :param res_accurate: :param business_exception: :return: ''' # 参数化 deviceCode = deviceCode json_dict = { "equno": deviceCode, "time": TimeHelper.get_time_from_timestamp(), "randCode": StringHelper.random_string(16) } publicKey = utils.get_publicKey_from_mysql(deviceCode) # RSA加密方法 rsa = utils.RSA() data = rsa.rsa_pubkey_encrypt(publicKey, json.dumps(json_dict)) # 发送业务请求 res_json = self.bns_device_auth( headers=headers, deviceCode=deviceCode, data=data, ) # 定义一个http状态码的白名单, 如果状态码不在白名单中,则直接返回 white_list = [200, 201] # 获取当前请求的http状态码 http_code = JsonHelper.parseJson_by_objectpath(res_json, "$.response_code") # 如果请求返回的状态码不是期望的http状态码, 则直接返回该状态码 if http_code not in white_list: return res_json # 提取业务码 actually_business_code = JsonHelper.parseJson_by_objectpath( res_json, "$.response_data.resultCode") # 异常码集合 exception_list = [ # 400004, # 设备类型不合法 ] # 正常业务状态码下, 函数的返回信息 if actually_business_code == 0: # 解析返回信息或调用自定义函数 data = JsonHelper.parseJson_by_objectpath(res_json, "$.response_data.data") res = rsa.rsa_pubkey_decrypt(publicKey, data) # 解密接口返回的信息 # 精确返回的内容 if res_accurate: pass # return deviceCode # 全部信息返回 info_dict = json.loads(res) return info_dict if info_dict else JsonHelper.parseJson_by_objectpath( res_json, "$.response_data") # 异常业务状态码下(已知异常), 函数的返回信息 elif actually_business_code in exception_list: if business_exception: raise DefinedBusinessException("接口已知业务异常:设备鉴权") return JsonHelper.parseJson_by_objectpath(res_json, "$.response_data") # 异常业务状态码下(未知异常), 函数的返回信息 else: raise UndefinedBusinessException("接口未知业务异常:设备鉴权")
# @Time : 2019/10/26 19:43 # @Author : 34801 # @Email : [email protected] # @File : gen_deviceData from base.helper import TimeHelper from testdata.simulate_upload import upload_by_netty def simulate_device_upload_pic(deviceCode, img_time=None, score=None, img_path=None, body_img_path=None, userStatus=None, capAngle=None): ''' 功能:模拟设备向云端上报图片 :return: ''' deviceCode, socket_addr, aes_key = upload_by_netty.get_device_connInfo(deviceCode) upload = upload_by_netty.UploadNetty(deviceCode, socket_addr, aes_key) upload.simulate_device_uploadPic(img_time=img_time, score=score, img_path=img_path, body_img_path=body_img_path, userStatus=userStatus, capAngle=capAngle) def simulate_device_login(device_no): ''' 功能:模拟设备向云端上报图片 :return: ''' device_no, socket_addr, aes_key = upload_by_netty.get_device_connInfo(device_no) upload_by_netty.UploadNetty(device_no, socket_addr, aes_key) if __name__ == '__main__': dev_code = "gmz4K81Wpjl8fN" simulate_device_upload_pic(dev_code, img_time=TimeHelper.get_custom_time(timestamp_offset=8000), score=1.2)