class PingxxApi(BaseApi): __auth = None __rsa_private = None __config = read_yaml(current=__file__, file_path="api.yml", key="PingxxApi") def __init__(self, request, logger, secret_key: str, rsa_private: str): """ 构造 PingxxApi 的方法 :param secret_key: 开发密钥 :param rsa_private: RSA商户私钥(需要整个字符串文本) """ # 调用父类,完成父类的构造方法 super().__init__(request=request, logger=logger) self.__auth = (secret_key, "") self.__rsa_private = rsa_private def _get_headers_for_signature(self, uri, request_body=None): """ 为签名验证构建请求头 :param uri: URL 去掉 https://{host},从 / 开始 注意:GET 请求需要传递全部的 uri,包含请求参数 :param request_body: 请求的正文,如果没有就不传 :return: dict 返回的 字典直接用来做 请求头 key 列表: - PingPlusPlus-Signature - PingPlusPlus-Request-Timestamp """ if self.__rsa_private is None or self.__rsa_private == "": return {} signature, timestamp = self.request.get_sign_by_pkcs115( rsa_private_key=self.__rsa_private, uri=uri, body_params=request_body) self.info("[%r] - 获取 Ping++ 验签的请求头,使用数据 uri=%s, params=%r" % (__name__, uri, request_body)) headers = { self._get_config(data_dict=self.__config, data_key="SIGN.HEADER_SIGNATURE"): signature, self._get_config(data_dict=self.__config, data_key="SIGN.HEADER_TIMESTAMP"): timestamp } return headers @property def auth(self): """ 认证【属性】 :return: """ return self.__auth
def test_charges_create(self, data): """ 执行测试的具体步骤 :param data: 通过读取 __test_data_collection 得到一条 test_data :return: None """ self.info("[%s] - 开始执行测试,使用数据:%r! " % (__name__, data)) # 准备数据 从 test_data 取数据 rsa_raw = data.get("RSA私钥") if rsa_raw is not None and rsa_raw != "": rsa_private = read_txt(current=__file__, file_path=rsa_raw) else: rsa_private = None extra_raw = data.get("extra") if extra_raw is not None and extra_raw != "": extra_value = read_yaml(current=__file__, file_path=extra_raw, key="%s/data/extra" % data.get("数据编号")) else: extra_value = None data_input_dict = dict( order_no=data.get("订单编号"), amount=data.get("金额"), channel=data.get("渠道"), currency=data.get("货币"), subject=data.get("主题"), body=data.get("正文"), description=data.get("描述"), extra=extra_value, app=dict(id=data.get("app")), client_ip=data.get("client_ip"), secret_key=data.get("密钥"), rsa_private=rsa_private, request=self.request, logger=self.logger ) # 调用业务,使用上面准备的数据 self.info("[%s] - 开始调用业务,使用数据 data_input_dict:%r! " % (__name__, data_input_dict)) resp = biz_create_charge(data_input_dict) # 对比结果,使用 test_data 取到的期望,和上一步执行得到的结果进行对比 self.info("[%s] - 开始进行断言,使用数据 resp:%r! " % (__name__, resp)) assert self.assert_equal(expected=data.get("期望状态码"), actual=resp.get("status_code")) assert self.assert_equal(expected=data.get("期望object"), actual=resp.get("object")) assert self.assert_equal(expected=bool(data.get("期望paid")), actual=resp.get("paid")) assert self.assert_equal(expected=data.get("渠道"), actual=resp.get("channel")) assert self.assert_equal(expected=data.get("金额"), actual=resp.get("amount")) self.info("[%s] - 结束执行测试,使用数据:%r! " % (__name__, data))
class LoginPage(ZentaoPage): """ author: ArtLinty email: [email protected] desc: 禅道企业版 登录页面业务 """ __config = read_yaml(current=__file__, file_path="web.yml", key="LoginPage") def login(self, account, password): """ 登录 :param account: :param password: :return: 当前 URL """ driver = self.driver driver.type(self._get_config(data_dict=self.__config, data_key="LOCATOR.ACCOUNT_INPUT"), account) driver.type(self._get_config(data_dict=self.__config, data_key="LOCATOR.PASSWORD_INPUT"), password) driver.click(self._get_config(data_dict=self.__config, data_key="LOCATOR.SUBMIT_BUTTON")) self.info("[%s] - 使用数据登录: %r" % (__name__, dict(account=account, password=password))) return self.current_url def set_language(self, language): """ 设定语言 :param language: zh_hans: 中文简体 zh_hant: 中文繁体 en: 英文 de: 德语 :return: """ if language is not None and isinstance(language, str): language = language.lower().strip() else: language = "" if language in ["zh_hans", "zh_hant", "en", "de"]: language_selector = "LOCATOR.%s_MENU" % language.upper() self.driver.click(self._get_config(data_dict=self.__config, data_key="LOCATOR.LANGUAGE_BUTTON")) self.driver.click(self._get_config(data_dict=self.__config, data_key=language_selector)) self.info("[%s] - 设定语言为 %s" % (__name__, language_selector)) return self.driver.get_text(self._get_config( data_dict=self.__config, data_key="LOCATOR.LANGUAGE_BUTTON" ))
class LifeApi(SeniverseApi): """ 标题: 生活类,生活模块的所有接口 作者: 刘挺立 日期: 20190820 邮件: [email protected] """ __config = read_yaml(current=__file__, file_path="api.yml", key="LifeApi") def suggest(self, data_dict): """ 生活指数 :param data_dict: :return: """ req_uri = self._get_config(self.__config, "SUGGEST.URI") req_method = self._get_config(self.__config, "SUGGEST.METHOD") req_data = { self._get_config(self.__config, "SUGGEST.PARAM.KEY"): self.api_key, self._get_config(self.__config, "SUGGEST.PARAM.LOCATION"): data_dict.get("location"), self._get_config(self.__config, "SUGGEST.PARAM.LANGUAGE"): data_dict.get("language") } req_data = self._remove_none_param(req_data) # 认证 req_cookies = {} # 真正的发请求 self._send(uri=req_uri, method=req_method, data_dict=req_data, cookies=req_cookies) # 返回响应的结果 resp_body_key_list = self._get_config(self.__config, "SUGGEST.RESP.DATA_KEY") resp = self._parse(body_key_list=resp_body_key_list) # 处理 list list_data_key = self._get_config(self.__config, "SUGGEST.RESP.LIST.DATA_KEY") index = self._get_config(self.__config, "SUGGEST.RESP.LIST.INDEX") sub_data_key_list = self._get_config(self.__config, "SUGGEST.RESP.LIST.SUB_DATA_KEY") list_resp = self._parse_list(list_data_key=list_data_key, index=index, sub_data_key_list=sub_data_key_list) return self._merge_dict(resp, list_resp)
class IndexPage(LoginPage): """ author: ArtLinty email: [email protected] desc: 禅道企业版 主页 业务 """ __config = read_yaml(current=__file__, file_path="web.yml", key="IndexPage") def get_real_name(self): """ 获取右上角真实姓名 :return: """ self.info("[%s] - 获取真实姓名! " % __name__) return self.driver.get_text(self._get_config(data_dict=self.__config, data_key="LOCATOR.REAL_NAME_SPAN")) def is_menu_active(self, menu: str): """ 判断菜单是否处于激活状态 :param menu: my, product, project, qa, ops, oa, feedback, doc, report, company, admin :return: """ if menu.strip() != "": menu = menu.lower().strip() if menu in ["my", "product", "project", "qa", "ops", "oa", "feedback", "doc", "report", "company", "admin"]: selector = self._get_config(data_dict=self.__config, data_key="LOCATOR.%s_LI" % menu.upper()) else: selector = None if selector is not None: self.info("[%s] - 获取菜单的选中状态,数据是 %r! " % (__name__, dict(menu=menu))) return "active" in self.driver.get_attribute( selector, "class" ) return None
class WeatherApi(SeniverseApi): """ 标题: 天气类,天气模块的所有接口 作者: 梁静 日期: 190826 邮件: [email protected] """ __config = read_yaml(current=__file__, file_path="api.yml", key="WeatherApi") def now(self, data_dict): """ 当前天气 :param self: :param data_dict: :return: """ req_uri = self._get_config(self.__config, "NOW.URI") self.info("[%s] - 使用 URI %r " % (__name__, req_uri)) req_method = self._get_config(self.__config, "NOW.METHOD") self.info("[%s] - 使用 METHOD %r " % (__name__, req_method)) req_data = { self._get_config(self.__config, "NOW.PARAM.KEY"): self.api_key, self._get_config(self.__config, "NOW.PARAM.LOCATION"): data_dict.get("location"), self._get_config(self.__config, "NOW.PARAM.LANGUAGE"): data_dict.get("language"), self._get_config(self.__config, "NOW.PARAM.UNIT"): data_dict.get("unit") } self.info("[%s] - 开始使用 参数 %r " % (__name__, req_data)) req_data = self._remove_none_param(req_data) self.info("[%s] - 完成去空 参数 %r " % (__name__, req_data)) # 认证 req_cookies = {} # 真正的发请求 self._send(uri=req_uri, method=req_method, data_dict=req_data, cookies=req_cookies) self.info("[%s] - 发送请求,使用数据如下 %r " % (__name__, dict(uri=req_uri, method=req_method, data_dict=req_data, cookies=req_cookies))) # 返回响应的结果 resp_body_key_list = self._get_config(self.__config, "NOW.RESP.LIST.DATA_KEY") self.info("[%s] - 读取响应数据键 %r " % (__name__, resp_body_key_list)) resp = self._parse(body_key_list=resp_body_key_list) self.info("[%s] - 收到 响应 %r " % (__name__, resp)) # 处理list list_data_key = self._get_config(self.__config, "NOW.RESP.LIST.DATA_KEY") index = self._get_config(self.__config, "NOW.RESP.LIST.INDEX") sub_data_key_list = self._get_config(self.__config, "NOW.RESP.LIST.SUB_DATA_KEY") list_resp = self._parse_list(list_data_key=list_data_key, index=index, sub_data_key_list=sub_data_key_list) self.info("[%s] - 收到自定义解析响应 %r" % (__name__, list_resp)) resp_result = self._merge_dict(resp, list_resp) self.info("[%s] - 合并之前的解析 %r 和刚刚的自定义解析 %r " % (__name__, resp, list_resp)) return resp_result
class TestLogin(BaseTest): """ author: ArtLinty email: [email protected] desc: 测试测试禅道登录业务 """ __test = dict( collection=read_csv(current=__file__, file_path="test_login.csv"), url=read_yaml(current=__file__, file_path="../../config/env_active.yml", key="zentao.url"), title="在登录页面,使用合法数据登录,操作成功", case="https://dwz.cn/GUIf2ZeN", feature="登录", story="系统登录操作", tag=("web", "zentao", "login", "valid"), severity=allure.severity_level.CRITICAL ) @pytest.fixture(autouse=True) def prepare(self): """ 测试固件 :return: """ self.init_logger(__name__) self.init_driver(url=self.__test.get("url")) yield self.close_driver() @allure.feature(__test.get("feature")) @allure.story(__test.get("story")) @allure.tag(*__test.get("tag")) @allure.severity(__test.get("severity")) @allure.testcase(url=__test.get("case")) @allure.title(__test.get("title")) @pytest.mark.parametrize("data", __test.get("collection")) def test_login(self, data): """ 测试登录,合法数据正常登录 :param data: :return: """ account = data.get("account") password = data.get("password") language = data.get("language") actual_lang_button_text = biz_set_language( driver=self.driver, language=language, logger=self.logger ) self.snapshot("在登录页面设置语言后截图=%r" % data) self.info("[%s] - 在登录页面设置语言,使用数据: %r" % (__name__, dict(language=language))) assert self.assert_equal(expected=data.get("exp_button_lang"), actual=actual_lang_button_text) current_url, actual_real_name = biz_get_real_name_after_login( driver=self.driver, account=account, password=password, logger=self.logger ) self.info( "[%r]-登录禅道, 使用数据 account=%r, password=%r" % (__file__, account, password) ) self.snapshot("登录后截图数据=%r" % data) expected = data.get("expected_url") assert self.assert_in( expected=expected, actual=current_url ), "登录后URL地址不对, expected=%r, actual=%r, 当前数据=%r" % (expected, current_url, data) expected = data.get("expected_real_name") assert self.assert_in( expected=expected, actual=actual_real_name ), "登录后 realname 地址不对, expected=%r, actual=%r, 当前数据=%r" % (expected, actual_real_name, data)
class ChargeApi(PingxxApi): """ 标题: 业务类,普通支付模块的所有接口 作者: 刘挺立 日期: 20190819 邮件: [email protected] """ __config = read_yaml(current=__file__, file_path="api.yml", key="ChargeApi") def create(self, data_dict: dict): """ 真实的调用 POST /v1/charges 接口 :param data_dict: dict 需要的key order_no amount, channel, currency, subject, body, description, extra: 需要是个字典,根据 channel app: 需要是个字典,{"id": your_app_id} :return: """ # 格式化处理请求的数据 # URI req_uri = self._get_config(self.__config, "CREATE.URI") req_method = self._get_config(self.__config, "CREATE.METHOD") req_data = { self._get_config(self.__config, "CREATE.PARAM.APP"): data_dict.get("app"), self._get_config(self.__config, "CREATE.PARAM.ORDER_NO"): data_dict.get("order_no"), self._get_config(self.__config, "CREATE.PARAM.CHANNEL"): data_dict.get("channel"), self._get_config(self.__config, "CREATE.PARAM.AMOUNT"): data_dict.get("amount"), self._get_config(self.__config, "CREATE.PARAM.CLIENT_IP"): data_dict.get("client_ip"), self._get_config(self.__config, "CREATE.PARAM.CURRENCY"): data_dict.get("currency"), self._get_config(self.__config, "CREATE.PARAM.SUBJECT"): data_dict.get("subject"), self._get_config(self.__config, "CREATE.PARAM.BODY"): data_dict.get("body"), self._get_config(self.__config, "CREATE.PARAM.DESCRIPTION"): data_dict.get("description"), self._get_config(self.__config, "CREATE.PARAM.EXTRA"): data_dict.get("extra") } req_data = self._remove_none_param(req_data) # 认证 req_auth = self.auth req_cookies = {} req_headers = self._get_headers_for_signature(uri=req_uri, request_body=req_data) # 真正的发请求 self._send(uri=req_uri, method=req_method, data_dict=req_data, auth=req_auth, cookies=req_cookies, headers=req_headers) # 返回响应的结果 resp_body_key_list = self._get_config(self.__config, "CREATE.RESP.DATA_KEY") return self._parse(body_key_list=resp_body_key_list) def view(self, charge_id: str): """ 真实的调用 GET /v1/charges/{charge_id} 接口 :param charge_id: :return: """ # 格式化处理请求的数据 req_uri = self._get_config(self.__config, "VIEW.URI") % charge_id req_method = self._get_config(self.__config, "VIEW.METHOD") req_auth = self.auth req_cookies = {} req_headers = self._get_headers_for_signature(uri=req_uri) # 真正的发请求 self._send(uri=req_uri, method=req_method, auth=req_auth, cookies=req_cookies, headers=req_headers) resp_body_key_list = self._get_config(self.__config, "VIEW.RESP.DATA_KEY") return self._parse(body_key_list=resp_body_key_list) def query(self, data_dict: dict): """ 真实的调用 GET /v1/charges/xxxx=xxxx 接口 :param data_dict: :return: """ # 格式化处理请求的数据 req_uri = self._get_config(self.__config, "VIEW.URI") req_method = self._get_config(self.__config, "VIEW.METHOD") req_data = { self._get_config(self.__config, "CREATE.PARAM.APP.get(id)"): data_dict.get("app"), self._get_config(self.__config, "CREATE.PARAM.LIMIT"): data_dict.get("limit"), self._get_config(self.__config, "CREATE.PARAM.CHANNEL"): data_dict.get("channel"), self._get_config(self.__config, "CREATE.PARAM.REFUNDED"): data_dict.get("refunded"), self._get_config(self.__config, "CREATE.PARAM.REVERSED"): data_dict.get("reversed"), self._get_config(self.__config, "CREATE.PARAM.PAID"): data_dict.get("paid"), self._get_config(self.__config, "CREATE.PARAM.CREATED_GT"): data_dict.get("created_gt"), self._get_config(self.__config, "CREATE.PARAM.CREATED_LT"): data_dict.get("created_lt"), self._get_config(self.__config, "CREATE.PARAM.CREATED_GTE"): data_dict.get("created_gte"), self._get_config(self.__config, "CREATE.PARAM.CREATED_LTE"): data_dict.get("created_lte") } req_data = self._remove_none_param(req_data) req_uri = encode_url(url=req_uri, params=req_data) req_auth = self.auth req_cookies = {} req_headers = self._get_headers_for_signature(uri=req_uri) # 真正的发请求 self._send(uri=req_uri, method=req_method, auth=req_auth, cookies=req_cookies, headers=req_headers) resp_body_key_list = self._get_config(self.__config, "VIEW.RESP.DATA_KEY") return self._parse(body_key_list=resp_body_key_list) def reverse(self, charge_id): """ 真实的调用 POST .v1.charges.{charge_id}.reverse 接口 :param charge_id: :return: """ # 格式化处理请求的数据 # URI # 格式化处理请求的数据 req_uri = self._get_config(self.__config, "REVERSE.URI") % charge_id req_method = self._get_config(self.__config, "REVERSE.METHOD") req_auth = self.auth req_cookies = {} req_headers = self._get_headers_for_signature(uri=req_uri) # 真正的发请求 self._send(uri=req_uri, method=req_method, auth=req_auth, cookies=req_cookies, headers=req_headers) resp_body_key_list = self._get_config(self.__config, "REVERSE.RESP.DATA_KEY") return self._parse(body_key_list=resp_body_key_list)
class TestWeatherNow(BaseTest): """ 标题: 在天气指数接口,使用合法有效的数据请求 查询天气指数接口,查询成功 作者: 梁静 时间: 20190826 邮件: [email protected] """ __test = dict( collection=read_csv(current=__file__, file_path="test_weather_now.csv"), config=read_yaml(current=__file__, file_path="../../config/env_active.yml", key="seniverse"), title="在天气指数接口,使用合法有效的数据请求 查询天气指数接口,查询成功", case="", feature="天气接口", story="天气接口的查询", tag=("api", "seniverse", "view", "valid"), severity=allure.severity_level.NORMAL ) @pytest.fixture(autouse=True) def prepare(self): """ 测试执行使用的测试固件,包含前置条件和清理操作 :return: """ # 首先是前置条件,在yeild之前 # 准备日志条件,就可以记录整个测试 self.init_logger(__name__) # 准备请求对象,就可以传递请求给业务,也可以对请求进行抓包截图 self.init_request( schema=parse_dict(dict_data=self.__test, data_key="config.schema"), host=parse_dict(dict_data=self.__test, data_key="config.host") ) # 是 yeild 的关键字,代表执行test_ 开头的方法的具体内容 self.info("[%s]- 完成测试的前置条件 set_up! " % __name__) yield # 接下来是 清理操作 self.close_request() self.wait() self.info("[%s]- 完成测试的清理操作 tear_up!" % __name__) @allure.feature(__test.get("feature")) @allure.story(__test.get("story")) @allure.tag(*__test.get("tag")) @allure.severity(__test.get("severity")) @allure.testcase(url=__test.get("case")) @allure.title(__test.get("title")) @pytest.mark.parametrize("data", __test.get("collection")) def test_weather_now(self, data): """ 执行测试的具体步骤 :param data: 通过读取__test_data_collection 得到一套 test_data :return: none """ self.info("[%s]-开始执行测试 ,使用数据:%r !" % (__name__, data)) # 准备数据 从test_data 取数据 data_input_dict = dict( api_key=data.get("私钥"), location=data.get("location"), language=data.get("language"), unit=data.get("unit"), request=self.request, logger=self.logger ) # 调用业务,使用上面的数据 self.info("[%s]-调用业务,使用数据data_input_dict:%r !" % (__name__, data_input_dict)) resp = biz_view_weather_now(data_input_dict) # 对比结果,使用test_data取得的期望,和上一步取得的结果进行对比 self.info("[%s]-开始进行断言,使用rasp:%r !" % (__name__, resp)) assert self.assert_equal(expected=data.get("期望状态码"), actual=resp.get("status_code")) assert self.assert_equal(expected=data.get("期望城市名称"), actual=resp.get("location.name")) assert self.assert_equal(expected=data.get("期望国家代号"), actual=resp.get("location.country")) assert self.assert_equal(expected=data.get("期望城市代码"), actual=resp.get("location.id")) self.info("[%s]-结束执行测试,使用数据:%r !" % (__name__, data))
class VvtechApi(BaseApi): __token = None __config = read_yaml(current=__file__, file_path="api.yml", key="VvtechApi") def login(self, data_dict: dict): """ 登录 :param data_dict: :return: """ req_uri = self._get_config(self.__config, "LOGIN.URI") req_method = self._get_config(self.__config, "LOGIN.METHOD") req_data = { self._get_config(self.__config, "SIGN.BODY_VV_SIGNATURE"): data_dict.get("vv_signature"), self._get_config(self.__config, "SIGN.BODY_VV_TIME"): data_dict.get("vv_time"), self._get_config(self.__config, "LOGIN.PARAM.PASSWORD"): data_dict.get("password"), self._get_config(self.__config, "LOGIN.PARAM.IS_ANDROID"): data_dict.get("is_android"), self._get_config(self.__config, "LOGIN.PARAM.CLIENT_ID"): data_dict.get("client_id"), self._get_config(self.__config, "LOGIN.PARAM.MOBILE"): data_dict.get("mobile"), self._get_config(self.__config, "LOGIN.PARAM.VERSION"): data_dict.get("version") } req_data = self._remove_none_param(req_data) # 认证 # 真正的发请求 self._send(uri=req_uri, method=req_method, data_dict=req_data) # 返回响应的结果 resp_body_key_list = self._get_config(data_dict=self.__config, data_key="LOGIN.RESP.DATA_KEY") resp = self._parse(body_key_list=resp_body_key_list) data_key_token = self._get_config(self.__config, "LOGIN.RESP.DATA_KEY_TOKEN") self.__token = parse_dict(dict_data=resp, data_key=data_key_token) return resp def _get_body_for_signature(self, token, request_body=None): """ 为签名验证构建请求头 :param uri: URL 去掉 https://{host},从 / 开始 注意:GET 请求需要传递全部的 uri,包含请求参数 :param request_body: 请求的正文,如果没有就不传 :return: dict 返回的 字典直接用来做 请求头 key 列表: - PingPlusPlus-Signature - PingPlusPlus-Request-Timestamp """ if self.token is None or self.token == "": token = self.token signature, timestamp = self.request.get_sign_by_md5( token=token, body_params=request_body) self.info("[%r] - 获取 VVTECH 验签的请求正文,使用数据 token=%s, params=%r" % (__name__, token, request_body)) body = { self._get_config(data_dict=self.__config, data_key="SIGN.BODY_VV_SIGNATURE"): signature, self._get_config(data_dict=self.__config, data_key="SIGN.BODY_VV_TIME"): timestamp } return body @property def token(self): """ 认证【属性】 :return: """ return self.__token
class WithdrawApi(VvtechApi): """ 标题: 业务类,普通支付模块的所有接口 作者: 刘挺立 日期: 20190819 邮件: [email protected] """ __config = read_yaml(current=__file__, file_path="api.yml", key="WithdrawApi") def add(self, data_dict: dict): """ 真实的调用 POST /v1/charges 接口 :param data_dict: dict 需要的key order_no amount, channel, currency, subject, body, description, extra: 需要是个字典,根据 channel app: 需要是个字典,{"id": your_app_id} :return: """ # 格式化处理请求的数据 # URI req_uri = self._get_config(self.__config, "ADD.URI") req_method = self._get_config(self.__config, "ADD.METHOD") token = data_dict.get("token") if token is None or token == "": token = self.token req_data = { self._get_config(self.__config, "ADD.PARAM.PASSWORD"): data_dict.get("password"), self._get_config(self.__config, "ADD.PARAM.BANK_CARD_ID"): data_dict.get("bank_card_id"), self._get_config(self.__config, "ADD.PARAM.AMOUNT"): data_dict.get("amount"), self._get_config(self.__config, "ADD.PARAM.APP_SECRET"): data_dict.get("app_secret") } req_data = self._remove_none_param(req_data) # 认证 req_body = self._get_body_for_signature(token=token, request_body=req_data) req_data_after_sign = self._merge_dict(first_dict=req_data, second_dict=req_body) req_data_after_sign[self._get_config(self.__config, "ADD.PARAM.TOKEN")] = token # 真正的发请求 self._send(uri=req_uri, method=req_method, data_dict=req_data_after_sign) # 返回响应的结果 resp_body_key_list = self._get_config(self.__config, "ADD.RESP.DATA_KEY") return self._parse(body_key_list=resp_body_key_list)
class TestChargesCreate(BaseTest): """ 标题: 在支付对象接口,使用合法有效的数据请求 创建支付的接口,创建成功 作者: 刘挺立 时间: 20190813 邮件: [email protected] """ __test = dict( collection=read_csv(current=__file__, file_path="test_charges_create.csv"), config=read_yaml(current=__file__, file_path="../../config/env_active.yml", key="pingxx"), title="在支付对象接口,使用合法有效的数据请求,创建支付的接口,创建成功", case="https://dwz.cn/GUIf2ZeN", feature="支付接口", story="支付对象的创建", tag=("api", "pingxx", "create", "valid"), severity=allure.severity_level.CRITICAL ) @pytest.fixture(autouse=True) def prepare(self): """ 测试执行使用的测试固件,包含前置条件和清理操作 :return: None """ # 首先是前置条件,在 yield 之前 # 准备日志文件,就可以记录整个测试 self.init_logger(__name__) # 准备请求对象,就可以传递请求给业务,也可以对请求进行抓包截图 self.init_request( schema=parse_dict(dict_data=self.__test, data_key="config.schema"), host=parse_dict(dict_data=self.__test, data_key="config.host") ) # 是 yield 关键字,代表执行 test_ 开头的方法的具体内容 self.info("[%s] - 完成测试的前置条件 set_up! " % __name__) yield # 最后是清理操作,在 yield 之后 self.wait() self.info("[%s] - 完成测试的清理操作 tear_down! " % __name__) @allure.feature(__test.get("feature")) @allure.story(__test.get("story")) @allure.tag(*__test.get("tag")) @allure.severity(__test.get("severity")) @allure.testcase(url=__test.get("case")) @allure.title(__test.get("title")) @pytest.mark.parametrize("data", __test.get("collection")) def test_charges_create(self, data): """ 执行测试的具体步骤 :param data: 通过读取 __test_data_collection 得到一条 test_data :return: None """ self.info("[%s] - 开始执行测试,使用数据:%r! " % (__name__, data)) # 准备数据 从 test_data 取数据 rsa_raw = data.get("RSA私钥") if rsa_raw is not None and rsa_raw != "": rsa_private = read_txt(current=__file__, file_path=rsa_raw) else: rsa_private = None extra_raw = data.get("extra") if extra_raw is not None and extra_raw != "": extra_value = read_yaml(current=__file__, file_path=extra_raw, key="%s/data/extra" % data.get("数据编号")) else: extra_value = None data_input_dict = dict( order_no=data.get("订单编号"), amount=data.get("金额"), channel=data.get("渠道"), currency=data.get("货币"), subject=data.get("主题"), body=data.get("正文"), description=data.get("描述"), extra=extra_value, app=dict(id=data.get("app")), client_ip=data.get("client_ip"), secret_key=data.get("密钥"), rsa_private=rsa_private, request=self.request, logger=self.logger ) # 调用业务,使用上面准备的数据 self.info("[%s] - 开始调用业务,使用数据 data_input_dict:%r! " % (__name__, data_input_dict)) resp = biz_create_charge(data_input_dict) # 对比结果,使用 test_data 取到的期望,和上一步执行得到的结果进行对比 self.info("[%s] - 开始进行断言,使用数据 resp:%r! " % (__name__, resp)) assert self.assert_equal(expected=data.get("期望状态码"), actual=resp.get("status_code")) assert self.assert_equal(expected=data.get("期望object"), actual=resp.get("object")) assert self.assert_equal(expected=bool(data.get("期望paid")), actual=resp.get("paid")) assert self.assert_equal(expected=data.get("渠道"), actual=resp.get("channel")) assert self.assert_equal(expected=data.get("金额"), actual=resp.get("amount")) self.info("[%s] - 结束执行测试,使用数据:%r! " % (__name__, data))
class TestWithdrawAdd(BaseTest): """ 标题: 在支付对象接口,使用合法有效的数据请求 创建支付的接口,创建成功 作者: 刘挺立 时间: 20190813 邮件: [email protected] """ __test = dict(collection=read_csv(current=__file__, file_path="test_withdraw_add.csv"), config=read_yaml(current=__file__, file_path="../../config/env_active.yml", key="vvtech"), title="在支付对象接口,使用合法有效的数据请求,创建支付的接口,创建成功", case="https://dwz.cn/GUIf2ZeN", feature="取款接口", story="取款对象的创建", tag=("api", "vvtech", "add", "valid"), severity=allure.severity_level.CRITICAL) @pytest.fixture(autouse=True) def prepare(self): """ 测试执行使用的测试固件,包含前置条件和清理操作 :return: None """ # 首先是前置条件,在 yield 之前 # 准备日志文件,就可以记录整个测试 self.init_logger(__name__) # 准备请求对象,就可以传递请求给业务,也可以对请求进行抓包截图 self.init_request(schema=parse_dict(dict_data=self.__test, data_key="config.schema"), host=parse_dict(dict_data=self.__test, data_key="config.host")) # 是 yield 关键字,代表执行 test_ 开头的方法的具体内容 self.info("[%s] - 完成测试的前置条件 set_up! " % __name__) yield # 最后是清理操作,在 yield 之后 self.wait() self.info("[%s] - 完成测试的清理操作 tear_down! " % __name__) @allure.feature(__test.get("feature")) @allure.story(__test.get("story")) @allure.tag(*__test.get("tag")) @allure.severity(__test.get("severity")) @allure.testcase(url=__test.get("case")) @allure.title(__test.get("title")) @pytest.mark.parametrize("data", __test.get("collection")) def test_charges_create(self, data): """ 执行测试的具体步骤 :param data: 通过读取 __test_data_collection 得到一条 test_data :return: None """ self.info("[%s] - 开始执行测试,使用数据:%r! " % (__name__, data)) # 准备数据 从 test_data 取数据 data_input_dict = dict(vv_vv_signature=data.get("签名"), vv_time=data.get("时间戳"), app_secret=data.get("密钥"), client_id=data.get("客户编号"), password=data.get("密码"), is_android=data.get("平台"), mobile=data.get("手机号"), version=data.get("版本"), amount=data.get("金额"), bank_card_id=data.get("卡号"), request=self.request, logger=self.logger) # 调用业务,使用上面准备的数据 self.info("[%s] - 开始调用业务,使用数据 data_input_dict:%r! " % (__name__, data_input_dict)) resp, resp2 = biz_add_withdraw(data_input_dict) # 对比结果,使用 test_data 取到的期望,和上一步执行得到的结果进行对比 self.info("[%s] - 开始进行断言,使用数据 resp:%r! " % (__name__, resp)) assert self.assert_equal(expected=data.get("期望状态码"), actual=resp.get("status_code")) assert self.assert_equal(expected=data.get("期望状态码"), actual=resp2.get("status_code")) assert self.assert_int_equal(expected=data.get("期望flag"), actual=resp2.get("flag")) self.info("[%s] - 结束执行测试,使用数据:%r! " % (__name__, data))
class TestLifeSuggest(BaseTest): """ 标题: 在生活指数接口,使用合法有效的数据请求 查询生活指数的接口,查询成功 作者: 刘挺立 时间: 20190814 邮件: [email protected] """ __test = dict(collection=read_csv(current=__file__, file_path="test_life_suggest.csv"), config=read_yaml(current=__file__, file_path="../../config/env_active.yml", key="seniverse"), title="在生活指数接口,使用合法有效的数据请求 查询生活指数的接口,查询成功", case="https://dwz.cn/GUIf2ZeN", feature="生活接口", story="生活指数的查询", tag=("api", "seniverse", "view", "valid"), severity=allure.severity_level.CRITICAL) @pytest.fixture(autouse=True) def prepare(self): """ 测试执行使用的测试固件,包含前置条件和清理操作 :return: None """ # 首先是前置条件,在 yield 之前 # 准备日志文件,就可以记录整个测试 self.init_logger(__name__) # 准备请求对象,就可以传递请求给业务,也可以对请求进行抓包截图 self.init_request(schema=parse_dict(dict_data=self.__test, data_key="config.schema"), host=parse_dict(dict_data=self.__test, data_key="config.host")) # 是 yield 关键字,代表执行 test_ 开头的方法的具体内容 self.info("[%s] - 完成测试的前置条件 set_up! " % __name__) yield # 最后是清理操作,在 yield 之后 self.wait() self.info("[%s] - 完成测试的清理操作 tear_down! " % __name__) @allure.feature(__test.get("feature")) @allure.story(__test.get("story")) @allure.tag(*__test.get("tag")) @allure.severity(__test.get("severity")) @allure.testcase(url=__test.get("case")) @allure.title(__test.get("title")) @pytest.mark.parametrize("data", __test.get("collection")) def test_life_suggest(self, data): """ 执行测试的具体步骤 :param data: 通过读取 __test_data_collection 得到一条 test_data :return: None """ self.info("[%s] - 开始执行测试,使用数据:%r! " % (__name__, data)) # 准备数据 从 test_data 取数据 data_input_dict = dict(api_key=data.get("私钥"), location=data.get("location"), language=data.get("language"), request=self.request, logger=self.logger) # 调用业务,使用上面准备的数据 self.info("[%s] - 开始调用业务,使用数据 data_input_dict:%r! " % (__name__, data_input_dict)) resp = biz_view_life_suggestion(data_input_dict) # 对比结果,使用 test_data 取到的期望,和上一步执行得到的结果进行对比 self.info("[%s] - 开始进行断言,使用数据 resp:%r! " % (__name__, resp)) assert self.assert_equal(expected=data.get("期望状态码"), actual=resp.get("status_code")) assert self.assert_equal(expected=data.get("期望城市名称"), actual=resp.get("location.name")) assert self.assert_equal(expected=data.get("期望国家代号"), actual=resp.get("location.country")) self.info("[%s] - 结束执行测试,使用数据:%r! " % (__name__, data))