def data(self, index, agrs): """ 返回 用列 测试 data 数据列表 :param index: 列表的索引位置 :param agrs: 字段的key 因为测试数据是可变的增加的 :return: """ if self.isredis: dataList = self.redi_all() else: dataList = self.get_yaml() if index < self.dataCount(): for data in dataList: # 如果用列等于当前 用列就返回 并且读取的是 yaml 数据 if data.get('casename' ) == self.case_name and self.isredis == False: return data.get('data')[index].get(agrs) elif data.get( 'casename') == self.case_name and self.isredis == True: # 读取是redis 时 data.get('data') 是字符串需要转为字典 列表 return eval(data.get('data'))[index].get(agrs) logger.error( f'{self.case_name}用列只有{self.dataCount()}条数据,你输入了第{index} 条!')
def setup(self): try: webdrivers = webdriver.Remote("http://" + APIUMHOST + "/wd/hub", self.decide_appos) return webdrivers except Exception as e: logger.error(f'初始app失败 {e}') raise ErrorExcep("初始app失败!!!!")
def receiving_argv(cls): """ 接收系统输入参数 1模块名称 2线程数据 3失败重跑次数 4生成结果目录名称 Python run.py all 1 1 demo :return: """ # 1模块名称 try: module_name = sys.argv[1] mlist = None if ',' in module_name: mlist = module_name.split(',') # 2线程数据 thread_num = sys.argv[2] # 3失败重跑次数 reruns = sys.argv[3] # 4 生成结果目录名称 results_dir = sys.argv[4] if int(thread_num) <= 0 or int(thread_num) is None: thread_num = 1 if int(reruns) <= 0 or int(reruns) is None: reruns = 1 return results_dir, module_name, mlist, thread_num, reruns except Exception as e: logger.error(e) raise ErrorExcep('输入参数错误!')
def __if_acceaaibilityid_predicate(self, locate, operate=None, text=None, el=None, index=None): """ * 私有不继承 判断 accessibilityid执行操作 :param locate: 表达 或者定位元素 :param operate: 执行操作 类型input(输入) , clear(清除) , clear_continue_input(清除在输入) 、click(点击) ,text(提取文本) , slide(滑动) :param text: 输入文本内容 :param el: 输入文本内容 :return: """ if operate is None: return self.accessibility_id(locate=locate, el=el) if operate in ('text', 'click', 'input', 'clear', 'clear_continue_input', 'slide'): if operate == 'text': # 提取文本、多个时需要传递index 参数 self.accessibility_id_text(locate=locate, el=el, index=index) elif operate == 'click': # 点击操作 、多个时需要传递index 参数 self.accessibility_id_click(locate=locate, el=el, index=index) elif operate == 'input': # 输入操作 、 多个时需要传递index 参数 if text is not None: self.accessibility_id_input(locate=locate, text=text, el=el, index=index) logger.error('accessibility_id_input 函数必须传递 text 参数') elif operate == 'clear': # 清除操作 self.accessibility_id_clear(locate=locate, el=el, index=index) elif operate == 'clear_continue_input': # 清除后在输入操作 if text is not None: self.accessibility_id_clear_continue_input(locate=locate, text=text, el=el, index=index) elif operate == 'slide': # 滑动操作 if index is None: index = 1 self.scroll_page_one_time(direction=locate, swipe_times=index) else: logger.error( f""" accessibilityid不支持输入参数{operate}!! 目前只支持:input(输入) , clear(清除) , clear_continue_input(清除在输入) 、click(点击) ,text(提取文本)、 slide(滑动) """) raise ErrorExcep( f""" accessibilityid不支持输入参数{operate}!! 目前只支持:input(输入) , clear(清除) , clear_continue_input(清除在输入) 、click(点击) ,text(提取文本)、 slide(滑动) """)
def android_uiautomator(self, locate, el=None): """ 更具表达式 查询页面元素 此方法 只能安卓可用 :param locate: expression 表达式 如 :new UiSelector().text("显示") :param el: 单个/多个 默认 find_element=None 单个 / 如果 find_element = 's' 代表多个 :return: str drive对象 """ try: logger.warning('此定位方法只android系统!!!') if el is not None: # 多个定位 # android_uiautomator_driver = self.driver.find_elements_by_android_uiautomator(locate) android_uiautomator_driver = WebDriverWait( self.driver, timeout=IMPLICITLY_WAIT_TIME, poll_frequency=POLL_FREQUENCY).until( lambda x: x.find_elements_by_android_uiautomator(locate )) else: # 单个定位 # android_uiautomator_driver = self.driver.find_element_by_android_uiautomator(locate) android_uiautomator_driver = WebDriverWait( self.driver, timeout=IMPLICITLY_WAIT_TIME, poll_frequency=POLL_FREQUENCY).until( lambda x: x.find_element_by_android_uiautomator(locate )) return android_uiautomator_driver except Exception as e: logger.error(f'元素在显示等待时间 {IMPLICITLY_WAIT_TIME} 未出现!请检查元素是否存在!!')
def accessibility_id(self, locate, el=None): """ AccessibilityId 元素定位 Android : Android的content-desc属性对应AccessibilityId Ios : IOS的label和name属性都对应AccessibilityId定位方式 :param locate: 定位元素 :param find_element: 单个/多个 默认 find_element=None 单个 / 如果 find_element = 's' 代表多个 :return: 返回定位到的元素 driver """ try: if el is not None: # accessibilityId = self.driver.find_elements_by_accessibility_id(locate) accessibilityId = WebDriverWait( self.driver, timeout=IMPLICITLY_WAIT_TIME, poll_frequency=POLL_FREQUENCY).until( lambda x: x.find_elements_by_accessibility_id(locate) ) # 在显示等待时间去查询元素 else: # accessibilityId = self.driver.find_element_by_accessibility_id(locate) accessibilityId = WebDriverWait( self.driver, timeout=IMPLICITLY_WAIT_TIME, poll_frequency=POLL_FREQUENCY).until( lambda x: x.find_element_by_accessibility_id(locate)) return accessibilityId except Exception as e: logger.error(f'元素在显示等待时间 {IMPLICITLY_WAIT_TIME} 未出现!请检查元素是否存在!!')
def ios_predicate(self, locate, el=None): """ 更具表达式 查询页面元素 此方法 只能 iso 可用 :param locate: expression 表达式 如 :new UiSelector().text("显示") :param el: 单个/多个 默认 find_element=None 单个 / 如果 find_element = 's' 代表多个 :return: str drive对象 """ try: logger.warning('此定位方法只ios系统!!!') if el is not None: # ios_predicate = self.driver.find_elements_by_ios_predicate(locate) ios_predicate = WebDriverWait( self.driver, timeout=IMPLICITLY_WAIT_TIME, poll_frequency=POLL_FREQUENCY).until( lambda x: x.find_elements_by_ios_predicate(locate) ) # 在显示登陆时间内查询元素 else: # ios_predicate = self.driver.find_element_by_ios_predicate(locate) ios_predicate = WebDriverWait( self.driver, timeout=IMPLICITLY_WAIT_TIME, poll_frequency=POLL_FREQUENCY).until( lambda x: x.find_element_by_ios_predicate(locate)) return ios_predicate except Exception as e: logger.error( f'元素在显示等待时间 {IMPLICITLY_WAIT_TIME} 未出现!请检查元素是否存在!! {e}')
def setup(): try: caps = CAPA webdrivers = webdriver.Remote("http://" + APIUMHOST + ":" + APIUMPORT + "/wd/hub", caps) return webdrivers except Exception as e: logger.error(f'初始app失败 {e}') raise ErrorExcep("初始app失败!!!!")
def connMysql(cls): """ Mysql 连接 :return: str Mysql连接串 """ try: conn = pymysql.connect(**MYSQL) return conn except Exception as e: logger.error(f'Mysql客户端连接失败! {e}')
def accept(self): """ 警告框处理 确认 :return: """ try: accept = self.driver.switch_to.alert.accept() logger.info('警告框已确认') return accept except Exception as e: logger.error("查找alert弹出框异常-> {0}".format(e))
def alertText(self): """ 警告框处理 提取警告框文本 :return: """ try: accept = self.driver.switch_to.alert.text logger.info(f'警告框文本信息为 {accept}') return accept except Exception as e: logger.error("查找alert弹出框异常-> {0}".format(e))
def dismiss(self): """ 警告框处理 取消 :return: """ try: accept = self.driver.switch_to.alert.dismiss() logger.info('警告框已取消') return accept except Exception as e: logger.error("查找dismiss弹出框异常-> {0}".format(e))
def redis_connect(): """ 连接redis集群 :return: object """ try: redisconn = RedisCluster(startup_nodes=REDIS_CLUSTER, password=REDIS_CLUSTER_PASWORD) return redisconn except Exception as e: logger.error(f"错误,连接redis 集群失败 {e}") return False
def connOracle(cls): """ Oracle 连接客户端 :return: """ try: info = list(ORACLE.values()) db = cx_Oracle.connect(f'{info[0]}/{info[1]}@{info[2]}') cursor = db.cursor() return cursor except Exception as e: logger.error(f'连接Oracle客户端错误!{e}')
def inspect_url_code(self, url): """ 判断url 地址正常请求 """ try: rep = requests.get(url, timeout=5) # 默认设置5秒超时 code = rep.status_code if code == 200: return True else: return False except Exception as e: logger.error(f'请求地址异常{e}!!')
def switch_windows(self, index): """ 多窗口切换 :param index: 列表索引 all_handle的列表索引位置 :return: """ indexHandle = self.all_handle()[index] try: logger.info(f'窗口已经切换{indexHandle}') return self.driver.switch_to_window(indexHandle) except Exception as e: logger.error("查找窗口句柄handle异常-> {0}".format(e))
def open_yaml(self): """ 读取yaml文件 :return: dict """ try: with open(self.FLIE_PATH) as f: data = yaml.load(f, Loader=yaml.FullLoader) f.close() return data except Exception as e: logger.error(e) logger.error(f'读取yaml失败!{e}')
def select(cls, sql): """ Oracle sql 执行 :param sql: sql str :return: tupe """ try: conn = cls.connOracle() conn.execute(sql) select_data = conn.fetchall() conn.close() return select_data except Exception as e: logger.error(f'执行Oracle sql异常{e}')
def get(self, key): """ redis get 操作 :param key: 键 :return: """ vlaue = self.session.get(key) self.session.close() if vlaue != None: return vlaue else: logger.error('无此key') return None
def pHash(cls, img1: str, img2: str) -> int: """ 差值哈希算法对比 :param img1: 图片1 :param img2: 图片2 :return: """ try: hash1 = AlgorithmClassify.pHash(cv2.imread(img1)) hash2 = AlgorithmClassify.pHash(cv2.imread(img2)) n = cls.cmpHash(str(hash1), str(hash2)) logger.info(f'感知哈希算法相似度:{n}') return n except Exception as e: logger.error(f'对比差感知哈希错误:{e}')
def redi_all(self): """ redis 返回全部数据 :return: """ try: re = RedisPool() modellanme = self.modelname.replace( '.yaml', '') # modellanme 模块 redis 不读.yaml 后缀 unpacked_object = pickle.loads(re.session.get(modellanme)) return unpacked_object except TypeError as e: logger.error(e)
def select(cls, sql): """ SQL 操作 "select * from `case`" :param sql: str sql :return: tupe """ try: conn = cls.connMysql() cur = conn.cursor() cur.execute(sql) select_data = cur.fetchall() cur.close() conn.close() return select_data except Exception as e: logger.error(f'执行Mysql sql错误{e}')
def scroll_page_one_time(self, direction="up", swipe_times=1): """ 屏幕滑动 几次 :param direction: 方向 up: 从下往上 down: 从上往下 left: 从右往左 right: 从左往右 :param swipe_times: 默认1次 """ screen_size = self.driver.get_window_size() screen_width = screen_size["width"] screen_height = screen_size["height"] center_x = screen_width * 0.5 center_y = screen_height * 0.5 top_x = center_x top_y = screen_height * 0.25 down_x = center_x down_y = screen_height * 0.75 left_x = screen_width * 0.25 left_y = center_y right_x = screen_width * 0.75 right_y = center_y if direction == "up": for i in range(0, swipe_times): self.driver.swipe(down_x, down_y, top_x, top_y, 2000) time.sleep(0.5) elif direction == "down": for i in range(0, swipe_times): self.driver.swipe(top_x, top_y, down_x, down_y, 2000) time.sleep(0.5) elif direction == "left": for i in range(0, swipe_times): self.driver.swipe(right_x, right_y, left_x, left_y, 2000) time.sleep(0.5) elif direction == "right": for i in range(0, swipe_times): self.driver.swipe(left_x, left_y, right_x, right_y, 2000) time.sleep(0.5) else: logger.error("请输入正确的参数 up、left、right、down") raise Exception("请输入正确的参数 up、left、right、down")
def redis_conn(self): """ 连接redis 操作 :return: """ try: if not RedisPool.__Pool: RedisPool.__Pool = redis.ConnectionPool( host=REDIS.get('host'), port=REDIS.get('port'), password=REDIS.get('password'), db=REDIS.get('db')) session = redis.StrictRedis(connection_pool=RedisPool.__Pool) return session except Exception as e: logger.error(f'连接错误!{e}')
def waitForElement(self, types, locate): """ 等待元素被加载 配合 isElementExist 函数检查元素是否存在 :param types: 定位类型 used_operate 函数传递过来 :param locate: 定位器 :return: """ timeout = IMPLICITLY_WAIT_TIME poll = POLL_FREQUENCY try: wait = WebDriverWait(self.driver, timeout, poll_frequency=poll) element = wait.until(EC.presence_of_element_located((types, locate))) logger.info(f'等待页面元素 {locate} {types} 存在') return element except Exception as e: logger.error('等待元素错误,元素在等待时间内未出现!') logger.error(e)
def isElementDisplayed(self, types, locate): """ 检查元素是否可见 :param types:定位类型 :param locate: 定位器 :param element: :return: """ isDisplayed = False element = None if locate: element = self.used_operate(types, locate) if element is not None: isDisplayed = element.is_displayed() logger.info(f"Element is displayed with locate: {locate} and types: {types}") else: logger.error(f"Element is not displayed with locate: {locate} and types: {types}") return isDisplayed
def used_input(self, types, locate, text, el=None, index=None): """ 获取元素后输入 并支持键盘操作 :param types: 定位类型 :param locate: 定位元素或者 表达式 :param el: 单个/多个 默认 find_element=None 单个 / 如果 find_element = 's' 代表多个 :param index: 列表索引位置 find_element传递时 此值必填 :return: """ try: if el is not None and index is not None: self.used_operate(types=types, locate=locate, el=el)[index].send_keys(text) else: self.used_operate(types=types, locate=locate, ).send_keys(text) except Exception as e: if AttributeError: logger.error(f'未找到元素或此元素没有 {e}') else: logger.error(f'find_element 不为空时 index 参数必须传递!!{e}')
def used_clear(self, types, locate, el=None, index=None): """ 清除输入框 :param types: 定位类型 :param locate: 定位元素 :param el: 单个/多个 默认 find_element=None 单个 / 如果 find_element = 's' 多个 :param index: 列表索引位置 find_element传递时 此值必填 """ try: if el is not None and index is not None: self.used_operate(types=types, locate=locate, el=el)[index].clear() else: self.used_operate(types=types, locate=locate).clear() logger.warning('此定位方法只android系统!!!') except Exception as e: if AttributeError: logger.error(f'未找到元素或此元素没有 {e}') else: logger.error(f'find_element 不为空时 index 参数必须传递!!{e}')
def used_clear_continue_input(self, types, locate, text, el=None, index=None): """ 清除数据在输入 :param types: 定位类型 :param locate: 定位元素 :param text: 输入文本 :param el: 单个/多个 默认 find_element=None 单个 / 如果 find_element = 's' 多个 :param index: 列表索引位置 find_element传递时 此值必填 :return: """ try: self.used_clear(types=types, locate=locate, el=el, index=index) time.sleep(0.5) self.used_input(types=types, locate=locate, text=text, el=el, index=index) except Exception as e: if AttributeError: logger.error(f'未找到元素或此元素没有 {e}') else: logger.error(f'find_element 不为空时 index 参数必须传递!!{e}')
def used_operate(self, types, locate, el=None): """ 获取元素 此函数配合 isElementExist 检查元素是否存在 :param types: 定位类型 :param locator: 定位元素 :param el: 单个/多个 默认 find_element=None 单个 / 如果 find_element = 's' 多个 :return: driver 对象 """ types = self.get_by_type(types) if self.isElementExist(types, locate): if el is not None: # find_element 不为空时 查询多个 element = self.driver.find_elements(types, locate) else: # find_element 为空时 查询单个 element = self.driver.find_element(types, locate) return element else: logger.error('定位元素错误未找到!')