def get_page_img(self, page_action): # 命令规范: {XX页面_XX操作}_截图时间.png cur_time = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime()) file_path = os.path.join(screenshot_dir, "{}_{}.png".format(page_action, cur_time)) self.driver.save_screenshot(file_path) logger.info("截图保存在:{}".format(file_path))
def get_text(self, locator, page_action, timeout=20, poll_frequency=0.5, wait_exist=False): """ :param locator: :param page_action: :param timeout: :param poll_frequency: :return: """ # 等待元素存在 - 查找 ele = self.get_element(locator, page_action, timeout, poll_frequency, wait_exist=wait_exist) logger.info("在 {} 行为,获取元素 {} 的文本值。".format(page_action, locator)) try: txt = ele.text except: logger.exception("获取元素文本失败!") self.get_page_img(page_action) raise else: logger.info("文本值为:{}".format(txt)) return txt
def test_invest_success(self, back_home): logger.info(" **** 正向用例:登陆成功 检验:用户余额是否变化,标的可余额是否变化 ***** ") # 前置 - 步骤 - 断言 # 1、首页 - 选择第1个标,点击抢投标按钮 HomePage(back_home).click_first_invest_button() # 2、标页面 - 获取用户的 投资前的余额 bp = BidPage(back_home) user_money_before_invest = bp.get_user_left_money() # 2、标页面 - 获取标的 投资前的标余额 bid_money_before_invest = bp.get_bid_left_money() # 2、标页面 - 输入投资金额2000,点击投资按钮。 bp.invest(2000) # 3、标页面 - 点击查看并激活 bp.click_activation_button_on_success_popup() # 1、用户的钱少了没有 # 投资之前 - 投资之后 = 2000 # 用户页面 - 得到用户当前余额 user_money_after_invest = UserPage(back_home).get_user_left_money() # 2、标的可投余额少了没有 # 标前 - 标后 = 2000 # 用户页面 - 回退一次 UserPage(back_home).back_last_page().refresh_page() # 刷新页面, # 标页面 - 获取投资后的标余额 bid_money_after_invest = bp.get_bid_left_money() # 1、用户的钱少了没有 assert float(user_money_before_invest) - float( user_money_after_invest) == 2000 assert float(bid_money_before_invest) * 10000 - float( bid_money_after_invest) * 10000 == 2000
def get_element(self, locator, page_action, timeout=20, poll_frequency=0.5, wait=None): # 先等待元素可见或者存在 if wait: self.wait_page_contains_element(locator, page_action, timeout, poll_frequency) else: self.wait_ele_visible(locator, page_action, timeout, poll_frequency) logger.info("在 {} 行为,查找元素:{}".format(page_action, locator)) try: ele = self.driver.find_element(*locator) except: # 输出到日志 logger.exception("查找元素失败!") # 失败截取当前页面 self.get_page_img(page_action) raise else: return ele
def wait_page_contains_element(self, locator, page_action, timeout=20, poll_frequency=0.5): """ :param locator: :param page_action: :param timeout: :param poll_frequency: :return: """ logger.info("在 {} 行为,等待元素:{} 存在。".format(page_action, locator)) try: start = time.time() WebDriverWait(self.driver, timeout, poll_frequency).until( EC.presence_of_element_located(locator)) except: # 输出到日志 logger.exception("等待元素存在失败!") # 失败截取当前页面 self.get_page_img(page_action) raise else: end = time.time() logger.info("等待耗时为:{}".format(end - start))
class TestRecharge(unittest.TestCase): @classmethod def setUpClass(cls) -> None: # 得到登陆的用户名和密码 clear_EnvData_attrs() user, passwd = get_old_phone() # 登陆接口调用。 resp = send_requests("POST", "member/login", {"mobile_phone": user, "pwd": passwd}) # cls.member_id = jsonpath(resp.json(),"$..id")[0] # cls.token = jsonpath(resp.json(),"$..token")[0] # setattr(EnvData, "member_id", jsonpath(resp.json(), "$..id")[0]) setattr(EnvData, "member_id", str(jsonpath(resp.json(), "$..id")[0])) setattr(EnvData, "token", jsonpath(resp.json(), "$..token")[0]) def tearDown(self) -> None: if hasattr(EnvData,"money"): delattr(EnvData,"money") @data(*cases) def test_recharge(self, case): # 替换的数据 if case["request_data"].find("#member_id#") != -1: case = replace_case_by_regular(case) # 数据库 - 查询当前用户的余额 - 在提现之前 if case["check_sql"]: user_money_before_recharge = db.select_one_data(case["check_sql"])["leave_amount"] logger.info("提现前的用户余额:{}".format(user_money_before_recharge)) # 期望的用户余额。 提现之前的余额 - 提现的钱 recharge_money = json.loads(case["request_data"])["amount"] logger.info("提现的金额为:{}".format(recharge_money)) expected_user_leave_amount = round(float(user_money_before_recharge) - recharge_money, 2) logger.info("提现后的金额为:{}".format(expected_user_leave_amount)) # 更新期望的结果 - 将期望的用户余额更新到期望结果当中。 # case = replace_mark_with_data(case, "#money#", str(expected_user_leave_amount)) setattr(EnvData,"money",str(expected_user_leave_amount)) case =replace_case_by_regular(case) # 发起请求 - 给用户提现 response = send_requests(case["method"], case["url"], case["request_data"], token=EnvData.token) # 将期望的结果转成字典对象,再去比对 expected = json.loads(case["expected"]) # 断言 try: self.assertEqual(response.json()["code"], expected["code"]) self.assertEqual(response.json()["msg"], expected["msg"]) if case["check_sql"]: self.assertEqual(response.json()["data"]["id"], expected["data"]["id"]) self.assertEqual(response.json()["data"]["leave_amount"], expected["data"]["leave_amount"]) # 数据库 - 查询当前用户的余额 user_money_after_recharge = db.select_one_data(case["check_sql"])["leave_amount"] logger.info("提现之后的用户余额:{}".format(expected_user_leave_amount)) self.assertEqual("{:.2f}".format(expected["data"]["leave_amount"]), "{:.2f}".format(float(user_money_after_recharge))) except: logger.exception("断言失败!") raise
def init(): # 实例化driver,访问登陆页面 logger.info("========== class级 前置操作:打开谷歌浏览器,访问系统登陆页面 ===============") driver = webdriver.Chrome() driver.maximize_window() driver.get(g_data.login_url) yield driver logger.info("========== class级 后置操作:关闭谷歌浏览器,退出会话 ===============") driver.quit()
def test_invest_failed_no100(self, back_home): logger.info(" **** 异常用例:投资失败 检验:???? ***** ") # 前置 - 步骤 - 断言 # 1、首页 - 选择第1个标,点击抢投标按钮 HomePage(back_home).click_first_invest_button() # 2、标页面 - 输入投资金额50,点击投资按钮。 bp = BidPage(back_home) bp.invest(50) # 断言 assert bp.get_msg_on_invest_faild_popup() == "投标金额必须为100的倍数"
def test_manual_inquiry(self, login_accessToken, case): logger.info("===================== 开始执行测试用例 ===================") logger.info("该case的值是:{}".format(case)) inquiry_url = "jdx-qa-service/" + case["url"] param_data = case["param"] resp = send_requests(method="post", url=inquiry_url, header=1, data=param_data, token=login_accessToken) print(case["param"]) print("响应的结果是:{}".format(resp.json())) logger.info("===================== 测试用例执行结束 ===================")
def click_element(self, locator, page_action, timeout=20, poll_frequency=0.5): # 等待 - 查找 ele = self.get_element(locator, page_action, timeout, poll_frequency) # 点击 logger.info("在 {} 行为,点击元素:{}".format(page_action, locator)) try: ele.click() except: logger.exception("点击元素失败!") self.get_page_img(page_action) raise
def extract_data_from_response(extract_exprs, response_dict): """ 根据jsonpath提取表达式,从响应结果当中,提取数据并设置为环境变量EnvData类的类属性,作为全局变量使用。 :param extract_exprs: 从excel当中读取出来的,提取表达式的字符串。 :param response_dict: http请求之后的响应结果。 :return:Nonoe """ # 将提取表达式转换成字典 extract_exprs = eval(extract_exprs) logger.info("要转换成字典的表达式是:\n".format(extract_exprs)) # 遍历字典,key作为全局变量名,value是jsonpath提取表达式。 for key, value in extract_exprs.items(): # 提取 res = str(jsonpath.jsonpath(response_dict, value)[0]) logger.info("设置环境变量,key:{},value:{}".format(key, res)) #设置为环境变量 setattr(EnvData, key, res)
def input_text(self, locator, page_action, value, timeout=20, poll_frequency=0.5): # 等待 - 查找 ele = self.get_element(locator, page_action, timeout, poll_frequency) logger.info("在 {} 行为,给元素:{} 输入文本值:{}".format(page_action, locator, value)) try: ele.clear() ele.send_keys(value) except: logger.exception("元素输入文本失败!") self.get_page_img(page_action) raise
def get_attribute(self, locator, page_action, attr, timeout=20, poll_frequency=0.5, wait_exist=False): # 等待元素存在 - 查找 ele = self.get_element(locator, page_action, timeout, poll_frequency, wait_exist=wait_exist) logger.info("在 {} 行为,获取元素 {} 的 {} 属性值。".format(page_action, locator, attr)) try: value = ele.get_attribute(attr) except: logger.exception("获取元素文本失败!") self.get_page_img(page_action) raise else: logger.info("属性值为:{}".format(value)) return value
def login_accessToken(): #登陆获取refreshToken和token logger.info("前置条件:开始运行!") login_data = json.loads(conf.get("UserInfo", "login_account")) login_url = "jdx-account-service/app/authentication/captcha/register/login" resp = send_requests("post", url=login_url, data=login_data, header=5) resp_dict = resp.json() logger.info("前置条件:登陆成功!响应结果为{}".format(resp_dict)) #使用token获取accessToken refresh_token = jsonpath.jsonpath(resp_dict, "$..refreshToken")[0] token = jsonpath.jsonpath(resp_dict, "$..token")[0] token_data = {"refreshToken": refresh_token} token_url = "sj-api/auth/refresh-token" token_resp = send_requests("post", url=token_url, header=5, data=token_data, token=token) accessToken = jsonpath.jsonpath(token_resp.json(), "$..accessToken")[0] logger.info("前置条件:获取accessToken成功!它的值是:{}".format(accessToken)) yield accessToken
def back_last_page(self): logger.info("回退到上一页") self.driver.back() return self
def send_requests(method, url, header=1, data=None, token=None, verify = False): """ :param method: 请求的方法,POST或者GET :param url: 请求的地址,可以缺省 https://sjapi.aihuishou.com/ :param header: 做了封装处理,1的时候只需要1个header,5的时候需要5个header :param data: 请求参数 :param token: 请求的token :param verify: 默认是False,要不然会报SSL的错误 :return: """ logger.info("**************** 发起一次HTTP请求 ****************") logger.info("请求方法为:{}".format(method)) full_url = __handle_url(url) full_header = __handle_header(header, token) logger.info("请求url为:{}".format(full_url)) logger.info("请求数据为:{}".format(data)) # 根据请求类型,调用请求方法 method = method.upper() # 大写处理 if method == "GET": full_url = full_url.replace("https", "http") logger.info("get请求url为:{}".format(full_url)) resp = requests.get(full_url, data, headers = full_header, verify = verify) else: resp = requests.post(full_url, json=data, headers = full_header, verify = verify) logger.info("响应状态码为:{}".format(resp.status_code)) logger.info("响应数据为:{}".format(resp.json())) logger.info("***************** HTTP请求结束 *****************") return resp
def setUpClass(cls) -> None: logger.info("************添加项目开始执行********") clear_EnvData_attrs()
def tearDownClass(cls) -> None: logger.info("====== 注册模块用例 执行结束 ========")
def setUpClass(cls) -> None: logger.info("====== 注册模块用例 开始执行 ========")
def tearDownClass(cls) -> None: logger.info("************** 加标接口 结束测试 ************")
def setUpClass(cls) -> None: logger.info("************** 加标接口 开始测试 ************") # 清理 EnvData里设置的属性 clear_EnvData_attrs()
def tearDown(self) -> None: logger.info("登录用例执行结束")
def setUpClass(cls) -> None: logger.info("开始执行登录用例")
def send_requests(method, url, data=None, token=None): """ :param method: :param url: :param data:字典形式的数据。 :param token: :return: """ logger.info("发起一次HTTP请求") # 得到请求头 headers = __handle_header(token) # 得到完整的url - 拼接url url = __pre_url(url) # 请求数据的处理 - 如果是字符串,则转换成字典对象。 data = __pre_data(data) # 将请求数据转换成字典对象。 logger.info("请求头为:{}".format(headers)) logger.info("请求方法为:{}".format(method)) logger.info("请求url为:{}".format(url)) logger.info("请求数据为:{}".format(data)) # 根据请求类型,调用请求方法 method = method.upper() # 大写处理 if method == "GET": resp = requests.get(url, data, headers=headers) else: resp = requests.post(url, json=data, headers=headers) logger.info("响应状态码为:{}".format(resp.status_code)) logger.info("响应数据为:{}".format(resp.json())) return resp
def tearDownClass(cls) -> None: logger.info("************添加项目结束执行********")
def refresh_page(self): logger.info("刷新当前页面") self.driver.refresh() return self
def access(init): logger.info("========== class级 前置操作:登陆系统 ===============") LoginPage(init).login(*g_data.user) yield init