def locating_element(element, action=''): el_location = None try: el, value = get_elem(element) except: logger.exception( '定位元素:%s 失败!' % element) raise Exception('Locating the element:%s is Failure, no element in define' % element) wait = WebDriverWait(g.driver, element_wait_timeout) if el['by'].lower() in ('title', 'url', 'current_url'): return None elif action == 'CLICK': el_location = wait.until(EC.element_to_be_clickable( (getattr(By, el['by'].upper()), value))) else: el_location = wait.until(EC.presence_of_element_located( (getattr(By, el['by'].upper()), value))) try: if g.browserName.lower() in ('chrome'): g.driver.execute_script( "arguments[0].scrollIntoViewIfNeeded(true)", el_location) else: g.driver.execute_script( "arguments[0].scrollIntoView(false)", el_location) except: pass return el_location
def tearDownClass(cls): if g.exist == 1: try: if g.platform.lower() in ('desktop', ): w.close() except: logger.exception('清除测试环境失败!')
def parse_elements(): ''' 从excel文件中获取、解析元素表,存储到g.elements中 ''' try: g.elements = elements_format(data2dict(Excel(g.elements_file).read('elements'))) except: logger.exception('*** 解析元素表失败 ***') g.code = -1 sys.exit(g.code)
def ready(): ''' 测试准备工作:解析测试用例集 -> 解析全局变量 -> 初始化浏览器和窗口 -> 初始化 unittest.testcase :param sheet_name: excel格式的测试用例集 testcase 的格式: { 'id': 'Login_001', #用例编号 'title': 'Login OK', #用例标题 'condition': '', #前置条件 'designer': 'Leo', #设计者 'flag': '', #自动化标记 'result': '', #用例结果 'remark': '', #备注 'steps': [ { 'no': 1, #测试步骤 'keyword': '输入', #关键字 'page': '产品管系统登录页', #页面 'custom': , #frame 'element': [元素1,元素2], #元素 'data': {变量1:值1,变量2:值2}, #测试数据 'expected':{变量1:值1,变量2:值2}, #预期结果 'output': {变量1:值1,变量2:值2}, #输出数据 'score': '', #测试结果 'remark': '', #备注 'snippets': [[{},{},...],[],...] #调用的用例片段各步骤 }, {……} …… ] } testsuite 的格式:[testcase1,testcase2,testcase3,...] ''' # 1.从 Excel 获取、解析测试用例集 parse_suite(g.current_sheet_name) # 2.从 Csv 获取、解析全局变量 parse_var(g.current_sheet_name) # 3.初始化浏览器和窗口 try: g.set_driver() w.init() except: logger.exception('*** 初始化浏览器或窗口失败 ***') g.code = -1 sys.exit(g.code) # 4.初始化 unittest.testcase gentest()
def check_keyword(kw): ''' 将测试用例中的 ’操作‘值 解析为对应的关键字 :param kw: 测试用例中的’操作‘值 :return: 对应的关键字 ''' try: keyword = all_keywords.get(kw) return keyword except: logger.exception('操作关键字:%s 不存在' % kw) exit()
def analyze_suite(testsuite): ''' 将测试用例解析为可执行参数,如:打开首页,解析为:OPEN 127.0.0.1 :param testsuite: 解析前的测试用例集 :return: 解析后的测试用例集 解析后的testcase: { 'id': 'Login_001', #用例编号 'title': 'Login OK', #用例标题 'condition': '', #前置条件 'designer': 'Leo', #设计者 'flag': '', #自动化标记 'result': '', #用例结果 'remark': '', #备注 'steps': [ { 'control': '', #测试步骤逻辑控制 'no': 1, #测试步骤 'keyword': '输入', #关键字 'page': '产品管系统登录页', #页面 'custom': , #frame 'element': [元素1,元素2], #元素 'data': {变量1:值1,变量2:值2}, #测试数据 'expected':{变量1:值1,变量2:值2}, #预期结果 'output': {变量1:值1,变量2:值2}, #输出数据 'score': '', #测试结果 'remark': '' #备注 }, {……} …… ] } ''' try: for testcase in testsuite: for step in testcase['steps']: # 测试用例中的’操作‘值解析为对应的关键字 step['keyword'] = check_keyword(step['keyword']) # 将用英文逗号 或 双英文逗号 隔开的数据处理为 dict step['data'] = data_format(str(step['data'])) step['expected'] = data_format(str(step['expected'])) step['output'] = data_format(str(step['output'])) logger.debug('测试用例集已完成解析:\n' + str(testsuite)) return testsuite except: logger.exception('*** 解析测试用例集失败 ***') g.code = -1 sys.exit(g.code)
def parse_var(sheet_name): ''' 从外部csv文件中读取全局变量 :param sheet_name: csv文件名称的一部分 :return: 全局变量的值 ''' try: # 如果测试数据文件存在,则从该文件里读取一行数据,赋值到全局变量列表里 data_file = Path('data') / (g.project_name + '-' + sheet_name + '.csv') if data_file.is_file(): g.var = read_record(data_file) except: logger.exception('*** 初始化全局变量失败 ***') g.code = -1 sys.exit(g.code)
def import_suite(sheet_name): ''' 从excel文件中获取、转换测试用例集 :param sheet_name: excel表单形式的测试用例集 :return: 返回转换后的测试用例集 testsuite 是 testcase的list testcase是dict,其中steps是由测试步骤组成的list(步骤是dict结构) ''' try: testsuite = testsuite_format(data2dict(g.testcase_workbook.read(sheet_name))) logger.info('从Excel中读取测试用例集:\n' + json.dumps(testsuite, ensure_ascii=False, indent=4)) logger.info('从Excel中读取测试用例集成功!') return testsuite except: logger.exception('*** 从Excel中读取测试用例集失败 ***') g.code = -1 sys.exit(g.code)
def __call__(self, *args, **kwargs): if_result = '' if self.testcase: self.testcase['result'] = 'Pass' for index, step in enumerate(self.testcase.get('steps')): # if 为否,不执行 then 语句 if step['control'] == '>' and not if_result: step['score'] = '-' continue # if 为真,不执行 else 语句 if step['control'] == '<' and if_result: step['score'] = '-' continue logger.info('执行测试步骤: %s|%s|%s' % (step['no'], step['keyword'], step['element'])) try: # 变量替换 replace_dict(step['data']) replace_dict(step['expected']) if isinstance(step['element'], str): step['element'] = replace(step['element']) elif isinstance(step['element'], list): step['element'] = replace_list(step['element']) # 处理强制等待时间 t = step['data'].get('等待时间') if t: del step['data']['等待时间'] sleep(float(t)) if g.platform.lower() in ( 'desktop', ) and step['keyword'] in web_keywords: if step['keyword'] not in ('MESSAGE', '对话框'): # 判断页面是否已和窗口做了关联,如果没有,就关联当前窗口,如果已关联,则判断是否需要切换 w.switch_window(step['page']) # 切换 frame 处理,支持变量替换 frame = replace(step['custom']) w.switch_frame(frame) sleep(2) # 根据关键字调用关键字实现 getattr(web, step['keyword'].lower())(step) elif g.platform.lower() in ( 'ios', 'android') and step['keyword'] in mobile_keywords: # 切換 context 處理 context = replace(step['custom']).strip() current_context = w.switch_context(context) if w.current_context.startswith('WEBVIEW'): # 切换标签页 tab = step['data'].get('标签页') if tab: del step['data']['标签页'] g.driver.switch_to_window(w.windows[tab]) logger.info('Current Context: %s' % repr(w.current_context)) # 根据关键字调用关键字实现 getattr(mobile, step['keyword'].lower())(step) elif step['keyword'] in http_keywords: # 根据关键字调用关键字实现 getattr(http, step['keyword'].lower())(step) elif step['keyword'].lower() == 'execute': if step['page'] in ('SNIPPET', '用例片段'): step['snippets'] = [] result, step['snippets'] = getattr( common, step['keyword'].lower())(step) logger.info('用例片段执行结果:\n') logger.info(result) self.testcase['result'] = result if result != 'Pass': break # elif step['page'] in ('SCRIPT', '脚本'): # # 判断页面是否已和窗口做了关联,如果没有,就关联当前窗口,如果已关联,则判断是否需要切换 # w.switch_window(step['page']) # # 切换 frame 处理,支持变量替换 # frame = replace(step['custom']) # w.switch_frame(frame) # common.script(step) else: # 根据关键字调用关键字实现 getattr(common, step['keyword'].lower())(step) logger.info('执行测试步骤通过: %s|%s|%s' % (step['no'], step['keyword'], step['element'])) step['score'] = 'OK' # if 语句结果赋值 if step['control'] == '^': if_result = True # 操作后,等待0.2秒 sleep(0.2) except Exception as exception: file_name = g.project_name + '-' + g.sheet_name + '-' + g.start_time + \ '#' + self.testcase['id'] + \ '-' + str(step['no']) + '.png' snapshot_file = str(Path('snapshot') / file_name) if g.platform.lower() in ( 'desktop', ) and step['keyword'] in web_keywords: try: g.driver.get_screenshot_as_file(snapshot_file) except: logger.exception('*** 保存截图失败! ***') elif g.platform.lower() in ( 'ios', 'android') and step['keyword'] in mobile_keywords: try: g.driver.switch_to_default_content() w.current_context = 'NATIVE_APP' g.driver.get_screenshot_as_file(snapshot_file) except: logger.exception('*** 保存截图失败! ***') logger.exception( '执行测试步骤失败: %s|%s|%s' % (step['no'], step['keyword'], step['element'])) step['score'] = 'NO' # if 语句结果赋值 if step['control'] == '^': if_result = False continue self.testcase['result'] = 'Fail' step['remark'] += str(exception) break if self.testcase['condition'] in ['', None]: self.testcase['setup'] = g.setup_testcase if self.testcase['condition'] in ['teardown', 'TEARDOWN']: case = {} case['id'] = self.testcase.get('id') case['title'] = self.testcase.get('title') case['result'] = self.testcase.get('result') case['steps'] = self.testcase.get('steps') g.teardowns.append(case) assert self.testcase['result'] == 'Pass'