def start_activity(self, app_activity, **opts): message='start_activity: '+app_activity log.info(message) self.driver.start_activity(self.env.appium.get("appPackage"), app_activity, **opts) self.driver.wait_activity(app_activity, 10, interval=0.3) return self
def home(self, action: ElementActions): action.driver.wait_activity(self.activity, 8, interval=0.3) try: action.click(self.关闭初始化弹出窗, wait=3) except: log.info('无弹窗需要关闭,所以不会找到元素 关闭初始化弹出窗') action.tap(self.关闭初始化浮窗)
def generate_report(self): #给报告中添加执行环境信息 env_dict={} env=self.env.conf #修改把yaml格式改成对应的键值对 devices=env.get('devices') env.pop('devices') new_env=dict(env, **devices) env_dict.update(new_env) env_dict.update(self.conf.info) env_properties = {} for key0,value0 in env_dict.items(): for key,value in value0.items(): env_properties['{}.{}'.format(key0,key)]=str(value) try: with open( self.properties_path,'w',encoding='utf-8') as fp: jprops.store_properties(fp, env_properties) except: log.error('配置环境未输出到报告中') #执行生成报告命令 cmd = 'allure generate %s -o %s --clean' % (self.xml_report_path, self.html_report_path) try: Shell.invoke(cmd) log.info("测试报告成功生成") except: log.error("Html测试报告生成失败,确保已经安装了Allure-Commandline")
def check_page(Pages,action: ElementActions): #只能检测静态页面,即有固定进入方法的:pageinto pagesname_list=get_attrsname(Pages) for page_name in pagesname_list: page=getattr(Pages,page_name) #如果为静态页面时可通过page的跳转方法进入对应页面 if hasattr(page,'pageinto')==False: continue else: log.info(' ----检测静态页面: {}----'.format(page_name)) elements_name = get_attrsname(page) getattr(page,'pageinto')(action) # 对元素进行遍历查询 for element_name in elements_name: element=getattr(page,element_name) if isinstance(element,dict): if element.get('dynamic')==False: if element.get('switch')!=None: #如果该元素在当前页面有前置步骤,则执行该前置步骤 getattr(page,element.get('switch'))(action) action.is_element_exist(locator=element)
def find_ele_child_byelement(self, element_parent, locator_child, is_Multiple=False, wait=6): #通过父结点元素查找子结点元素,不支持name定位方式 if locator_child['type'] == 'name': log.error('find_ele_child_byelement的定位方式错误') raise NotFoundElementError value_child, type_child = locator_child['value'], locator_child['type'] try: WebDriverWait(self.driver, wait).until( lambda driver: element_parent.find_element(type_child, value_child)) log.info( "页面【{}】的元素【{}】成功查询到查找子节点 元素【{}】" .format(locator_child.get("page"), element_parent, locator_child.get('name'))) if is_Multiple == False: return element_parent.find_element(type_child, value_child) else: return element_parent.find_elements(type_child, value_child) except: log.info( "页面【{}】的元素【{}】未能查询到查找子节点 元素【{}】\n locator_child{}" .format(locator_child.get("page"), element_parent, locator_child.get('name'), locator_child)) if is_Multiple == False: return None else: return []
def is_text_displayed(self, text, retry_time=0, is_raise=False): """检查页面中是否有文本关键字 如果希望检查失败的话,不再继续执行case,使用 is_raise = True Args: text: 关键字(请确保想要的检查的关键字唯一) is_retry: 是否重试,默认为true retry_time: 重试次数,默认为5 is_raise: 是否抛异常 Returns: True: 存在关键字 Raises: 如果is_raise = true,可能会抛NotFoundElementError """ try: if retry_time!=0: result= WebDriverWait(self.driver, retry_time).until( lambda driver: self._find_text_in_page(text)) else: result=self._find_text_in_page(text) if result == True: log.info("[Text]页面中找到了 %s 文本" % text) return result except TimeoutException: log.error("[Text]页面中未找到 %s 文本" % text) if is_raise: raise NotFoundTextError else: return False
def _batch_exec_pytest(platform,current_device,testsuite_paths): # 通过多进程调度执行用例(多台设备) #testsuite_paths 为list ,格式为[tests/test_suit2,tests/test_suit3] log.info('Run task pid={} testsuite_paths: {}...'.format(os.getpid(), testsuite_paths)) #清除log对象已有的handler for handle in log.handlers: log.removeHandler(handle) # 定义handler的输出格式 formatter = logging.Formatter('pid:{} %(levelname)s %(message)s'.format(os.getpid()), "%H:%M:%S") #添加用于输出到控制台的handler console_handler=Logbuilder().get_consolehandler(formatter) log.addHandler(console_handler) run=Run(platform) #当前进程的环境对象通过回调写入current_device run.env.callback_current_device(current_device) #导入参数执行pytest args=testsuite_paths+run.get_run_args() pytest.main(args)
def driverenv(): env=EnvironmentAndroid() current_device=env.current_device capabilities = { 'platformName': current_device.get("platformName"), 'platformVersion': current_device.get("platformVersion"), 'deviceName': current_device.get("deviceName"), 'udid': current_device.get("deviceName"), 'systemPort':current_device.get('systemPort'), 'app': env.appium.get("app"), 'clearSystemFiles': True, 'appActivity': env.appium.get("appActivity"), 'appPackage': env.appium.get("appPackage"), 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, "unicodeKeyboard": True, "noReset":True, "fullReset":False, "newCommandTimeout": 300 } # systemPort=current_device.get('systemPort') # if systemPort!=None: # capabilities['systemPort']=systemPort # log.info('当前执行的appium相关配置为:'+str(capabilities)) host=current_device.get('appiumserver') driver = webdriver.Remote(host, capabilities) return driver
def pageinto(self, action: ElementActions): action.sleep(0.5).start_activity(self.activity) usercenterpage = UserCenterPage() # usercenterpage.pageinto(action) if action.find_ele(usercenterpage.注册登陆) != None: action.click(usercenterpage.注册登陆) else: log.info('app已是登陆状态,无法进入登陆页')
def check_pageset(Pagesset,action: ElementActions): #参数Pagesset为元素是Pages的list for Pages in Pagesset: log.info('\n ++++++检测静态页面集: {}++++++\n'.format(Pages.__name__)) check_page(Pages,action)
def is_element_exist(self, locator,wait=2): """检查元素是否存在""" if self._find_element(locator,is_raise=False,wait=wait)==None: log.error("没有查找到 页面【{}】的元素【{}】".format(locator.get("page"),locator.get("name"))) return False else: log.info("已查找到 页面【{}】的元素【{}】".format(locator.get("page"),locator.get("name"))) return True
def swip_right(self,count=1): """ 向右滑 """ for x in range(count): self.driver.swipe(self.width / 10, self.height / 2, self.width * 9/ 10, self.height / 2, 1000) log.info("----------向右滑动----------") return self
def swip_up(self, count=1): """向上滑动,常用于下拉刷新 Args: count: 滑动次数 """ for x in range(count): self.driver.swipe(self.width / 2, self.height *1 / 10, self.width / 2, self.height * 9 / 10, 1000) log.info("----------向上滑动---------") return self
def swip_left(self, count=1): """向左滑动,一般用于ViewPager Args: count: 滑动次数 """ for x in range(count): self.driver.swipe(self.width * 9 / 10, self.height / 2, self.width / 10, self.height / 2, 1000) log.info("----------向左滑动----------") return self
def get_conf(self): environment_info_path = str( os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, "data/config_android.yaml"))) log.info('获取环境配置 Path:' + environment_info_path) with open(environment_info_path, "r") as f: conf = yaml.load(f) return conf
def _find_text_in_page(self, text): """检查页面中是否有文本关键字 拿到页面全部source,暴力检查text是否在source中 Args: text: 检查的文本 Returns: True : 存在 """ log.info("[查找] 文本 %s " % text) return text in self.driver.page_source
def swip_down(self, count=1,half=False): """向下滑动,常用于下拉刷新 Args: count: 滑动次数 half:是否为滑动一半 """ for x in range(count): if half==False: self.driver.swipe(self.width / 2, self.height * 9 / 10, self.width / 2, self.height * 1 / 10, 1000) else: self.driver.swipe(self.width / 2, self.height * 3 / 5, self.width / 2, self.height * 1 / 5, 1000) log.info("---------向下滑动----------") return self
def _scheduling_process(self): #给多台设备分配测试任务的调度算法(简单平均调度) #其中suit1是文件夹的名字、device1是配置中device设备的key """ :return: { device1:[suit1,suit2] device2:[suit3,suit4] device3:[suit5] } """ tests_path=self.env.path.get('tests') suitname_list=ls_by_key(tests_path,'test') if len(suitname_list)==0 or len(self.devices)==0: raise IndexError('data is bad') task_num,mod =divmod(len(suitname_list),len(self.devices)) suitname_list_slice=[] tmp=[] count=0 for suitname in suitname_list: tmp.append(suitname) if count<(len(suitname_list)-mod): if len(tmp)==task_num: suitname_list_slice.append(tmp) tmp=[] count+=1 #对最后一个加入整除后剩余的 last_ele=suitname_list_slice[-1] suitname_list_slice[-1]=last_ele+tmp scheduling_info={} count=0 for device_key in self.devices: scheduling_info[device_key]=suitname_list_slice[count] count=count+1 log.info("多设备分配的测试集执行为: {}\n".format(str(scheduling_info))) return scheduling_info
def click(self, locator, count=1,wait=5): """基础的点击事件 Args: locator:定位器 count: 点击次数 """ msg="[点击] 页面【{}】的元素【{}】".format(locator.get("page"),locator.get("name")) log.info(msg) element = self._find_element(locator,wait=wait) self.click_ele(element,count,is_log=False) return self
def invoke(cmd, cwd=None, is_log=True): # shell设为true,程序将通过shell来执行 # stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。 # 他们可以是PIPE,文件描述符或文件对象,也可以设置为None,表示从父进程继承。 # subprocess.PIPE实际上为文本流提供一个缓存区 if is_log == True: log.info("执行命令: {}".format(cmd)) p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) output, errors = p.communicate() o = output.decode("utf-8") return o
def find_ele(self,locator,is_Multiple=False,wait = 5): #通过定位器查找元素,不用于断言(断言元素存在用 is_element_exist ,断言页面是否含有对应文本关键字的请用is_text_displayed) #需要查找多个时,返回list #没有查找到时,返回None 或 [] """ Args: locator: 定位器对象 is_Multiple: 是否查找多个 """ log.info("查找 页面【{}】的元素【{}】".format(locator.get("page"), locator.get("name"))) if is_Multiple==False: return self._find_element(locator,is_raise=False,wait=wait) else: return self._find_elements(locator,is_raise=False,wait=wait)
def get_text(self, locator): """获取元素中的text文本 查找到单个元素,返回文本字符串 Args: locator:定位器 count: 点击次数 Returns: 如果没有该控件返回None Examples: TextView 是否显示某内容 """ element = self._find_element(locator,wait=1) log.info("获取元素中的text文本\n locator: \n{}".format(locator)) return self.get_text_ele(element)
def tap(self,locator): #获取当前屏幕的分辨率,元素通过相对位置点击 """ :param locator: value格式为 "x,y" :return: """ if locator.get('type')!="tap": log.error('定位方式错误,不能通过坐标位置定位点击 \nlocator: {}'.format(str(locator))) else: position=locator.get('value').split(',') x=int(position[0])*self.width/1080 y=int(position[1])*self.height/1920 positions=[(x,y)] log.info("通过坐标({},{}), 成功点击 页面【{}】的元素【{}】".format(x,y,locator.get('page'),locator.get('name'))) self.driver.tap(positions,duration=400)
def text(self, locator, value, clear_first=False, click_first=True): """输入文本 Args: locator: 定位器 value: 文本内容 clear_first: 是否先清空原来文本 click_first: 是否先点击选中 Raises: NotFoundElementError """ element=self._find_element(locator) log.info("在【{}】页面 对元素【{}】输入文本【{}】".format(locator.get("page"), locator.get("name"), value)) self.text_ele(element,value,clear_first, click_first) return self
def test_case1(self, action): count = 5 action.click(p.特卖首页.发布) for index in range(count): action.click(p.特卖首页.发布_上传视频) videoele = action.find_ele(vp.视频发布页.视频选择, is_Multiple=True)[0] action.click_ele(videoele) action.click(vp.视频发布页.视频选择后下一步).click(vp.视频发布页.视频处理后下一步) action.sleep(8).click(vp.视频发布页.视频发布, wait=15) result = action.is_toast_show('视频发布成功', wait=20) log.info('result: {}'.format(result)) action.get_img('上传后截图') action.back_press()
def long_press(self,locator,time=2000): #长按操作,locator的type为tap时支持坐标位置长按 """ :param locator: :param time: 单位毫秒 :return: """ if locator.get('type')=="tap": position = locator.get('value').split(',') x = int(position[0]) * self.width / 1080 y = int(position[1]) * self.height / 1920 TouchAction(self.driver).long_press(x=x,y=y,duration=time).perform() else: ele=self._find_element(locator) TouchAction(self.driver).long_press(el=ele, duration=time).perform() log.info("[长按] 页面【{}】的元素【{}】".format(locator.get('page'), locator.get('name')))
def find_ele_fromparent(self,locator_tmp,locator_target,is_Multiple=False,wait=5): #通过uiautomator查找定位元素的兄弟节点元素,不支持xpath,且兄弟节点必须同级 """ 支持的定位方式有:text(name),description(特有的),id,class name """ log.info("页面【{}】通过元素【{}】查找兄弟元素【{}】".format(locator_tmp.get("page"), locator_tmp.get('name'), locator_target.get("name"))) map={ "name":"textContains", "description":"descriptionContains", "id":"resourceId", "class name":"className" } type_tmp=map.get(locator_tmp["type"]) type_target=map.get(locator_target["type"]) if type_tmp==None or type_target==None: log.error('当前定位方式不支持') raise NotFoundElementError value_tmp=locator_tmp["value"] value_target =locator_target["value"] ui_value='new UiSelector().{}(\"{}\").fromParent(new UiSelector().{}(\"{}\"))'.format(type_tmp,value_tmp,type_target,value_target) try: WebDriverWait(self.driver, wait).until( lambda driver: driver.find_element_by_android_uiautomator(ui_value)) if is_Multiple == False: return self.driver.find_element_by_android_uiautomator(ui_value) else: return self.driver.find_elements_by_android_uiautomator(ui_value) except: log.info('页面【{}】未找到 元素【{}】\n locator: {}'.format(locator_tmp.get("page"), locator_target.get('name'),str(locator_target))) if is_Multiple == False: return None else: return []
def _find_ele_child_byname(self, locator_parent, locator_child, is_Multiple=False, wait=8): #使用uiautomator通过父节点,定位子节点。 value_parent, type_parent = locator_parent['value'], locator_parent['type'] value_child, type_child = locator_child['value'], locator_child['type'] try: map = { "name": "textContains", "id": "resourceId", "class name": "className" } type_parent = map.get(type_parent) if type_parent == None: log.error('当前定位方式不支持') raise NotFoundElementError ui_value = 'new UiSelector().{}(\"{}\").childSelector(new UiSelector().textContains(\"{}\"))'.format( type_parent, value_parent, value_child) WebDriverWait(self.driver, wait).until( lambda driver: driver.find_element_by_android_uiautomator(ui_value)) log.info("页面【{}】的元素【{}】成功查找子节点 元素【{}】".format(locator_parent.get("page"), locator_parent.get("name"), locator_child.get('name'))) if is_Multiple == False: return self.driver.find_element_by_android_uiautomator(ui_value) else: return self.driver.find_elements_by_android_uiautomator(ui_value) except: log.info( "页面【{}】的元素【{}】未能查询到查找子节点 元素【{}】\n locator_parent:{} \n locator_child{}" .format(locator_parent.get("page"), locator_parent.get("name"), locator_child.get('name'), locator_parent, locator_child)) if is_Multiple == False: return None else: return []
def click_ele(self,element,count=1,is_log=True): #对元素对象进行点击 if is_log==True: log.info("[点击]{}次元素 {}".format(count,element)) if count == 1: element.click() else: touch_action = TouchAction(self.driver) try: for x in range(count): self.sleep(0.1, islog=False) touch_action.tap(element).perform() except: pass self.sleep(0.1, islog=False) return self
def is_toast_show(self, message, wait=5): """Android检查是否有对应Toast显示,常用于断言 Args: message: Toast信息 wait: 等待时间 Returns: True 显示Toast """ toast_loc = ("xpath", ".//*[contains(@text,'%s')]" % message) try: WebDriverWait(self.driver, wait, 0.2).until(expected_conditions.presence_of_element_located(toast_loc)) log.info("当前页面成功找到toast: %s" % message) return True except : log.error("当前页面中未能找到toast为: %s" % message) return False