def setup(self, testcase, case): logger.info('Start running the SETUP testcase...') # setup 执行成功标记 def run_setup(testcase): if testcase: tc = TestCase(testcase) tc.run() if testcase['result'] == 'success': flag = 'Y' else: flag = 'N' else: flag = 'O' return flag setup_flag = run_setup(deepcopy(self.setup_testcase)) if setup_flag == 'N': base_flag = run_setup(deepcopy(self.base_testcase)) if base_flag == 'Y': setup_flag = run_setup(deepcopy(self.setup_testcase)) if setup_flag == 'N': testcase['result'] = 'blocked' case.block('Blocked', 'SETUP is not success') logger.warn('Run the testcase: %s|%s blocked, SETUP is not success' % ( testcase['id'], testcase['title'])) return False elif base_flag == 'O': testcase['result'] = 'blocked' case.block('Blocked', 'SETUP is not success') logger.warn('Run the testcase: %s|%s blocked, SETUP is not success' % ( testcase['id'], testcase['title'])) return False return True
def switch_context(self, context): logger.info('ALL Contexts:%s' % g.driver.contexts) if context != self.current_context: if contex == '': context = None g.driver.switch_to.context(context) self.current_context = context
def close(self): all_handles = g.driver.window_handles for handle in all_handles: # 切换到每一个窗口,并关闭它 g.driver.switch_to_window(handle) g.driver.close() logger.info('--- Close th Windows: %s' % repr(handle))
def run(self): self.testsuite_start() # 当前测试用例 self.current = {'result': 'success'} # 上一个测试用例 self.previous = {} # 前置条件执行失败标志,即未执行用例阻塞标志 #-- self.blcoked_flag = False for testcase in self.testsuite: self.run_testcase(testcase) self.report.finish() self.testsuite += g.casesets # 把用例组合执行结果添加到末尾 # 2.清理环境 try: if g.platform.lower() in ('desktop', ): # w.close() g.driver.quit() logger.info('--- Quit th Driver: %s' % g.browserName) except: logger.exception('Clear the env is fail') self.testsuite_end()
def open(step): element = step['element'] value = e.get(element)[1] if step['data'].get('清理缓存', '') or step['data'].get('clear', ''): g.driver.delete_all_cookies() if step['data'].get('打开方式', '') == '新标签页' or step['data'].get('mode', '').lower() == 'tab': js = "window.open('%s')" % value g.driver.execute_script(js) # 判断是否打开了新的窗口,并将新窗口添加到所有窗口列表里 all_handles = g.driver.window_handles for handle in all_handles: if handle not in w.windows.values(): w.register(step, handle) else: if step['data'].get('打开方式', '') == '新浏览器' or step['data'].get('mode', '').lower() == 'browser': w.close() g.set_driver() w.init() g.driver.get(value) w.open(step) cookie = step['data'].get('cookie', '') if cookie: g.driver.add_cookie(json2dict(cookie)) co = g.driver.get_cookie(json2dict(cookie).get('name', '')) logger.info(f'cookie is add: {co}') sleep(0.5)
def switch_window(self, page): if self.new_window_flag: if page in list(self.pages): page = '通用' g.current_page = '通用' self.new_window_flag = False if page != '通用': if page not in list(self.pages): # 如果当前页未注册,则需要先清除和当前窗口绑定的页面 for k in list(self.pages): if self.current_window == self.pages[k]: self.pages.pop(k) # 在把当前窗口捆定到当前页面 self.pages[page] = self.current_window elif self.pages[page] != self.current_window: # 如果当前窗口为 HOME,则关闭之 if self.current_window == 'HOME': g.driver.close() self.windows.pop('HOME') # 再切换到需要操作的窗口 tw = self.windows[self.pages[page]] logger.info('--- Switch Windows: %s' % repr(tw)) g.driver.switch_to_window(tw) self.current_window = self.pages[page] logger.info('--- Current Windows: %s' % repr(self.current_window))
def web_check(self, step, element): def deep(src): # 把不需要比较的部分贴白 if self.expected.get('#blank'): blank(src, eval(self.expected.get('#blank'))) # 裁剪需要比较的部分 if self.expected.get('#cut'): cut(src, src, eval(self.expected.get('#cut'))) if Path(step['snapshot'].get('expected_screen', '')).is_file(): # 屏幕截图比较 image1 = Image.open(step['snapshot']['expected_screen']) image2 = Image.open(step['snapshot']['real_screen']) deep(step['snapshot']['real_screen']) histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt(reduce(operator.add, list( map(lambda a, b: (a - b)**2, histogram1, histogram2))) / len(histogram1)) diff = ImageChops.difference(image1.convert('RGB'), image2.convert('RGB')) if differ == 0.0: # 图片间没有任何不同 logger.info('SnapShot: screen_shot is the same') else: file_name = self.label + now() + 'diff_screen' + '.png' step['snapshot']['diff_screen'] = str( Path(self.snapshot_folder) / file_name) diff.save(step['snapshot']['diff_screen']) raise Exception('SnapShot: screen_shot is diff: %s' % differ) elif step['snapshot'].get('expected_screen'): get_screenshot(step['snapshot']['expected_screen']) deep(step['snapshot']['expected_screen']) if Path(step['snapshot'].get('expected_element', '')).is_file(): file_name = self.label + now() + '#element' + '[' + self.expected['#element_name'] + ']' + '.png' step['snapshot']['real_element'] = str(Path(self.snapshot_folder) / file_name) crop(element, step['snapshot']['real_screen'], step['snapshot']['real_element']) deep(step['snapshot']['real_element']) # 屏幕截图比较 image1 = Image.open(step['snapshot']['expected_element']) image2 = Image.open(step['snapshot']['real_element']) histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt(reduce(operator.add, list( map(lambda a, b: (a - b)**2, histogram1, histogram2))) / len(histogram1)) diff = ImageChops.difference(image1.convert('RGB'), image2.convert('RGB')) if differ == 0.0: logger.info('SnapShot: element_shot is the same') else: file_name = self.label + now() + 'diff_element' + '.png' step['snapshot']['diff_element'] = str( Path(self.snapshot_folder) / file_name) diff.save(step['snapshot']['diff_element']) raise Exception('SnapShot: element_shot is diff: %s' % differ) elif step['snapshot'].get('expected_element'): crop(element, step['snapshot']['real_screen'], step['snapshot']['expected_element']) deep(step['snapshot']['expected_element'])
def check(step): data = step['data'] if not data: data = step['expected'] element = step['element'] element_location = locating_element(element) if '#' in element: e_name = element.split('#')[0] + '#' else: e_name = element by = e.elements[e_name]['by'] output = step['output'] var = {} if by in ('title', 'current_url'): var[by] = getattr(Common, by)(data, output) else: for key in data: # 预期结果 expected = data[key] # 切片操作处理 s = re.findall(r'\[.*?\]', key) if s: s = s[0] key = key.replace(s, '') if key == 'text': real = element_location.text else: real = element_location.get_attribute(key) if s: real = eval('real' + s) logger.info('DATA:%s' % repr(expected)) logger.info('REAL:%s' % repr(real)) try: compare(expected, real) except: raise Exception( f'Check Failure, DATA:{repr(expected)}, REAL:{repr(real)}') # 获取元素其他属性 for key in output: if output[key] == 'text': var[key] = g.var[key] = element_location.text elif output[key] in ('text…', 'text...'): if element_location.text.endswith('...'): var[key] = g.var[key] = element_location.text[:-3] else: var[key] = g.var[key] = element_location.text else: var[key] = g.var[key] = element_location.get_attribute( output[key]) if var: step['_output'] += '\n||output=' + str(var) return element_location
def run(self, sheet_name): # 1.从 Excel 获取测试用例集 try: data = self.testcase_workbook.read(sheet_name) testsuite = testsuite_format(data) # logger.info('Testsuite imported from Excel:\n' + # json.dumps(testsuite, ensure_ascii=False, indent=4)) logger.info('From Excel import testsuite success') except: logger.exception('*** From Excel import testsuite fail ***') self.code = -1 sys.exit(self.code) # 2.初始化全局对象 try: g.init(self.desired_caps, self.server_url) g.set_driver() # 如果测试数据文件存在,则从该文件里读取一行数据,赋值到全局变量列表里 data_file = path.join('data', g.project_name + '-' + sheet_name + '.csv') if path.exists(data_file): g.var = get_record(data_file) data_file = path.join( 'data', g.project_name + '-' + sheet_name + '-globle.txt') if path.exists(data_file): g.var.update(get_all_record(data_file)) w.init() except: logger.exception('*** Init global object fail ***') self.code = -1 sys.exit(self.code) # 3.解析测试用例集 try: parse(testsuite) logger.debug('testsuite has been parsed:\n' + str(testsuite)) except: logger.exception('*** Parse testsuite fail ***') self.code = -1 sys.exit(self.code) # 4.执行测试套件 ts = TestSuite(testsuite, self.report_ts[sheet_name], self.conditions) ts.run() # 5.判断测试结果 if self.report_ts[sheet_name].high_errors + self.report_ts[sheet_name].medium_errors + \ self.report_ts[sheet_name].high_failures + self.report_ts[sheet_name].medium_failures: self.code = -1 # 6.保存测试结果 try: self.report_data[sheet_name] = testsuite2report(testsuite) data = testsuite2data(testsuite) self.report_workbook.write(data, sheet_name) except: logger.exception('*** Save the report is fail ***')
def web_check(self, step, element): if Path(self.expected.get('#ScreenShot', '')).is_file(): # 屏幕截图比较 image1 = Image.open(self.expected['#ScreenShot']) image2 = Image.open(step['#ScreenShot']) histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt( reduce( operator.add, list(map(lambda a, b: (a - b)**2, histogram1, histogram2))) / len(histogram1)) diff = ImageChops.difference(image1.convert('RGB'), image2.convert('RGB')) if differ == 0.0: # 图片间没有任何不同 logger.info('SnapShot: ScreenShot is the same') else: file_name = '#' + self.label + now() + '.png' step['#diffScreen'] = str( Path(self.snapshot_folder) / file_name) diff.save(step['#diffScreen']) raise Exception('SnapShot: ScreenShot is diff: %s' % differ) elif self.expected.get('#ScreenShot'): get_screenshot(self.expected['#ScreenShot']) if Path(self.expected.get('#ElementShot', '')).is_file(): file_name = self.label + now( ) + '#Element' + '[' + self.expected['#ElementName'] + ']' + '.png' step['#ElementShot'] = str(Path(self.snapshot_folder) / file_name) crop(element, step['#ScreenShot'], step['#ElementShot']) # 屏幕截图比较 image1 = Image.open(self.expected['#ElementShot']) image2 = Image.open(step['#ElementShot']) histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt( reduce( operator.add, list(map(lambda a, b: (a - b)**2, histogram1, histogram2))) / len(histogram1)) diff = ImageChops.difference(image1.convert('RGB'), image2.convert('RGB')) if differ == 0.0: logger.info('SnapShot: ElementShot is the same') else: file_name = '#' + self.label + now() + '#Element' + '.png' step['#diffElement'] = str( Path(self.snapshot_folder) / file_name) diff.save(step['#diffElement']) raise Exception('SnapShot: ElementShot is diff: %s' % differ) elif self.expected.get('#ElementShot'): crop(element, step['#ScreenShot'], self.expected['#ElementShot'])
def title(cls, data, output): logger.info('DATA:%s' % repr(data['text'])) logger.info('REAL:%s' % repr(g.driver.title)) if data['text'].startswith('*'): assert data['text'][1:] in g.driver.title else: assert data['text'] == g.driver.title # 只能获取到元素标题 for key in output: g.var[key] = g.driver.title
def current_url(cls, data, output): logger.info('DATA:%s' % repr(data['text'])) logger.info('REAL:%s' % repr(g.driver.current_url)) if data['text'].startswith('*'): assert data['text'][1:] in g.driver.current_url else: assert data['text'] == g.driver.current_url # 只能获取到元素 url for key in output: g.var[key] = g.driver.current_url
def windwos_check(self, dialog, step): element = step['element'] if Path(step['snapshot'].get('Expected_Screen', '')).is_file(): # 屏幕截图比较 image1 = Image.open(step['snapshot']['Expected_Screen']) image2 = Image.open(step['snapshot']['Real_Screen']) histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt(reduce(operator.add, list( map(lambda a, b: (a - b)**2, histogram1, histogram2))) / len(histogram1)) diff = ImageChops.difference(image1.convert('RGB'), image2.convert('RGB')) if differ == 0.0: # 图片间没有任何不同 logger.info('SnapShot: ScreenShot is the same') else: file_name = self.label + now() + 'Diff_Screen' + '.png' step['snapshot']['Diff_Screen'] = str( Path(self.snapshot_folder) / file_name) diff.save(step['snapshot']['Diff_Screen']) raise Exception('SnapShot: ScreenShot is diff: %s' % differ) elif step['snapshot'].get('Expected_Screen'): pic = dialog.capture_as_image() pic.save(step['snapshot']['Expected_Screen']) if Path(step['snapshot'].get('Expected_Element', '')).is_file(): file_name = self.label + now() + '#Element' + '.png' step['snapshot']['Real_Element'] = str(Path(self.snapshot_folder) / file_name) if dialog.backend.name == 'win32': pic = dialog.window(best_match=element).capture_as_image() elif dialog.backend.name == 'uia': pic = dialog.child_window(best_match=element).capture_as_image() pic.save(step['snapshot']['Real_Element']) # 屏幕截图比较 image1 = Image.open(step['snapshot']['Expected_Element']) image2 = Image.open(step['snapshot']['Real_Element']) histogram1 = image1.histogram() histogram2 = image2.histogram() differ = math.sqrt(reduce(operator.add, list( map(lambda a, b: (a - b)**2, histogram1, histogram2))) / len(histogram1)) diff = ImageChops.difference(image1.convert('RGB'), image2.convert('RGB')) if differ == 0.0: logger.info('SnapShot: ElementShot is the same') else: file_name = self.label + now() + 'Diff_Element' + '.png' step['snapshot']['Diff_Element'] = str( Path(self.snapshot_folder) / file_name) diff.save(step['snapshot']['Diff_Element']) raise Exception('SnapShot: ElementShot is diff: %s' % differ) elif step['snapshot'].get('Expected_Element'): if dialog.backend.name == 'win32': pic = dialog.window(best_match=element).capture_as_image() elif dialog.backend.name == 'uia': pic = dialog.child_window(best_match=element).capture_as_image() pic.save(step['snapshot']['Expected_Element'])
def switch_context(self, context): if context.strip() == '': context = 'NATIVE_APP' # logger.info('--- ALL Contexts:%s' % g.driver.contexts) # logger.info('--- Input Context:%s' % repr(context)) if context != self.current_context: if context == '': context = None logger.info('--- Switch Context:%s' % repr(context)) g.driver.switch_to.context(context) self.current_context = context
def run(self, sheet_name): # 1.从 Excel 获取测试用例集 try: data = self.testcase_workbook.read(sheet_name) testsuite = testsuite_format(data) # logger.info('Testsuite imported from Excel:\n' + # json.dumps(testsuite, ensure_ascii=False, indent=4)) logger.info('From Excel import testsuite success') except: logger.exception('*** From Excel import testsuite failure ***') self.code = -1 sys.exit(self.code) # 2.初始化全局对象 try: g.set_driver() # 如果测试数据文件存在,则从该文件里读取数据,赋值到全局变量列表里 data_file = Path('data') / (g.plan_name + '-' + sheet_name + '.csv') if data_file.is_file(): g.test_data = get_record(str(data_file)) w.init() except: logger.exception('*** Init global object failure ***') self.code = -1 sys.exit(self.code) # 3.解析测试用例集 try: parse(testsuite) logger.debug('testsuite has been parsed:\n' + str(testsuite)) except: logger.exception('*** Parse testsuite failure ***') self.code = -1 sys.exit(self.code) # 4.执行测试套件 g.ts = TestSuite(testsuite, sheet_name, self.junit_suite[sheet_name], self.conditions) g.ts.run() # 5.判断测试结果 if self.junit_suite[sheet_name].high_errors + self.junit_suite[sheet_name].medium_errors + \ self.junit_suite[sheet_name].high_failures + self.junit_suite[sheet_name].medium_failures: self.code = -1 # 6.保存测试结果 try: data = testsuite2data(testsuite) self.report_workbook.write(data, sheet_name) self.report_data[sheet_name] = testsuite2report(testsuite) except: logger.exception('*** Save the report is failure ***')
def title(cls, data, output): logger.info('DATA:%s' % repr(data['text'])) logger.info('REAL:%s' % repr(g.driver.title)) try: if data['text'].startswith('*'): assert data['text'][1:] in g.driver.title else: assert data['text'] == g.driver.title except: raise Exception( f'Check Failure, DATA:{data["text"]}, REAL:{g.driver.title}') # 只能获取到元素标题 for key in output: g.var[key] = g.driver.title
def message(step): data = step['data'] text = data.get('text', '') element = step['element'] el, value = e.get(element) if value.lower() in ('确认', 'accept'): g.driver.switch_to_alert().accept() elif value.lower() in ('取消', '关闭', 'cancel', 'close'): g.driver.switch_to_alert().dismiss() elif value.lower() in ('输入', 'input'): g.driver.switch_to_alert().send_keys(text) g.driver.switch_to_alert().accept() logger.info('--- Switch Frame: Alert') w.frame = 'Alert'
def current_url(cls, data, output): logger.info('DATA:%s' % repr(data['text'])) logger.info('REAL:%s' % repr(g.driver.current_url)) try: if data['text'].startswith('*'): assert data['text'][1:] in g.driver.current_url else: assert data['text'] == g.driver.current_url except: raise Exception( f'Check Failure, DATA:{data["text"]}, REAL:{g.driver.current_url}' ) # 只能获取到元素 url for key in output: g.var[key] = g.driver.current_url return g.driver.current_url
def command(step, name=None): cwd = os.getcwd() cmd = step['element'] if name and os.name != name: logger.info(f'COMMAND: this OS is not {name}, "{cmd}" is skipped') return if step['page']: os.chdir(step['page']) code = os.system(cmd) if step['page']: os.chdir(cwd) if code != 0: raise Exception(f'COMMAND: "{cmd}" is failure, code: {code}')
def sql(step): element = step['element'] _sql = e.get(element)[1] logger.info('SQL: %s' % repr(_sql)) # 获取连接参数 value = e.get(step['page'] + '-' + 'config')[1] arg = data_format(value) if step['page'] not in g.db.keys(): g.db[step['page']] = DB(arg) if _sql.lower().startswith('select'): row = g.db[step['page']].fetchone(_sql) logger.info('SQL result: %s' % repr(row)) if not row: raise Exception('*** Fetch None ***') else: g.db[step['page']].execute(_sql) result = {} if _sql.lower().startswith('select'): text = _sql[6:].split('FROM')[0].split('from')[0].strip() keys = dedup(text).split(',') for i, k in enumerate(keys): keys[i] = k.split(' ')[-1] result = dict(zip(keys, row)) logger.info('keys result: %s' % repr(result)) data = step['data'] if not data: data = step['expected'] if data: for key in data: sv, pv = data[key], result[key] logger.info('key: %s, expect: %s, real: %s' % (repr(key), repr(sv), repr(pv))) compare(sv, pv) output = step['output'] if output: logger.info('output: %s' % repr(output)) for key in output: g.var[key] = result[output[key]]
def sql(step): element = step['element'] el, _sql = e.get(element) logger.info('SQL: %s' % repr(_sql)) # 获取连接参数 el, value = e.get(step['page'] + '-' + 'config') arg = data_format(value) if step['page'] not in g.db.keys(): g.db[step['page']] = DB(arg) row = g.db[step['page']].fetchone(_sql) logger.info('SQL result: %s' % repr(row)) if not row: raise Exception('*** Fetch None ***') result = {} if _sql.lower().startswith('select'): keys = _sql[6:].split('FROM')[0].split('from')[0].strip().split(',') for i, k in enumerate(keys): keys[i] = k.split(' ')[-1] result = dict(zip(keys, row)) logger.info('keys result: %s' % repr(result)) data = step['data'] if data: for key in data: logger.info('key: %s, expect: %s, real: %s' % (repr(key), repr(data[key]), repr(result[key]))) if data[key].startswith('*'): assert data[key][1:] in result[key] else: assert data[key] == result[key] output = step['output'] if output: logger.info('output: %s' % repr(output)) for key in output: g.var[key] = result[output[key]]
def tab_name(step): element = step['element'] name = step['data']['text'] # 从所有窗口中查找给定元素,如果查询到就命名,否则报错 all_handles = g.driver.window_handles logger.info('All Handles: %s' % all_handles) flag = False for handle in all_handles: #logger.info('Page Source: %s \n%s' % (handle, g.driver.page_source)) #logger.info('All Windows: %s' %w.windows) if handle not in w.windows.values(): # 切换至此窗口 g.driver.switch_to_window(handle) try: # 成功定位到关键元素 locating_element(element, 'CLICK') # 添加到窗口资源池 g.windows w.windows[name] = handle # 把当前窗口名字改为新窗口名称 w.current_window = name flag = True logger.info('Current Window: %s' % repr(name)) logger.info('Current Handle: %s' % repr(handle)) except: pass if not flag: raise Exception( 'Tab Name failure: the element:%s in all tab is not found' % element)
def have(self, page, element): ele = element.split('#') if len(ele) >= 2: _el = ele[0] + '#' else: _el = element # 如果有<>,则不判断了 if '<' in _el: return '', '通用' + '-' + element # 在元素定位表中查询 elem = page + '-' + _el if self.elements.get(elem, ''): return self.elements[elem]['custom'], page + '-' + element else: # 查不到就在通用里查,还是查不到,可能是不在 element.xlsx 中定义的元素 elem = '通用' + '-' + _el if self.elements.get(elem, ''): return self.elements[elem]['custom'], '通用' + '-' + element else: logger.info('Page:%s element:%s' % (page, element)) return '', element
def switch_frame(self, frame): if frame.strip(): frame = [x.strip() for x in frame.split('|')] if frame != self.frame: if self.frame != 0: g.driver.switch_to.default_content() for f in frame: logger.info('--- Frame Value: %s' % repr(f)) if f.startswith('#'): f = int(f[1:]) elif '#' in f: from sweetest.testcase import elements_format from sweetest.locator import locating_element element = elements_format('通用', f)[2] f = locating_element(element) logger.info('--- Switch Frame: %s' % repr(f)) g.driver.switch_to.frame(f) self.frame = frame else: if self.frame != 0: g.driver.switch_to.default_content() self.frame = 0
def check(step): data = step['data'] element = step['elements'][0] element_location = locating_element(element) if '#' in element: e_name = element.split('#')[0] + '#' else: e_name = element by = e.elements[e_name]['by'] output = step['output'] if by in ('title', 'current_url'): getattr(Common, by)(data, output) else: for key in data: if key == 'text': logger.info('DATA:%s' % data[key]) logger.info('REAL: %s' % element_location.text) if data[key].startswith('*'): assert data[key][1:] in element_location.text else: assert element_location.text == data[key] else: logger.info('DATA:%s' % data[key]) logger.info('REAL: %s' % element_location.get_attribute(key)) if data[key].startswith('*'): assert data[key][1:] in element_location.get_attribute(key) else: assert element_location.get_attribute(key) == data[key] # 获取元素其他属性 for key in output: if output[key] == 'text': g.var[key] = element_location.text elif output[key] in ('text…', 'text...'): if element_location.text.endswith('...'): g.var[key] = element_location.text[:-3] else: g.var[key] = element_location.text else: g.var[key] = element_location.get_attribute(output[key])
def run(self): logger.info('Run the TestCase: %s|%s' % (self.testcase['id'], self.testcase['title'])) self.testcase['result'] = 'Pass' self.testcase['report'] = '' if_result = '' for index, step in enumerate(self.testcase['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('Run the Step: %s|%s|%s' % (step['no'], step['keyword'], step['element'])) step['page'], step['custom'], step['element'] = elements_format( step['page'], 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): for i in range(len(step['element'])): step['element'][i] = replace(step['element'][i]) step['vdata'] = v_data(step['data']) # 处理强制等待时间 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) # 根据关键字调用关键字实现 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', '用例片段'): result, steps = getattr(common, step['keyword'].lower())(step) self.testcase['result'] = result self.snippet_steps[index + 1] = steps 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('Run the Step: %s|%s|%s is Pass' % (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 = 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('*** save the screenshot is fail ***') 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('*** save the screenshot is fail ***') logger.exception( 'Run the Step: %s|%s|%s is Failure' % (step['no'], step['keyword'], step['element'])) step['score'] = 'NO' # if 语句结果赋值 if step['control'] == '^': if_result = False continue self.testcase['result'] = 'Fail' self.testcase['report'] = 'step-%s|%s|%s: %s' % ( step['no'], step['keyword'], step['element'], exception) step['remark'] += str(exception) break steps = [] i = 0 for k in self.snippet_steps: steps += self.testcase['steps'][i:k] + self.snippet_steps[k] i = k steps += self.testcase['steps'][i:] self.testcase['steps'] = steps
def check(dialog, step): element = step['element'] data = step['data'] if not data: data = step['expected'] output = step['output'] for key in data: # 预期结果 expected = data[key] # 切片操作处理 s = re.findall(r'\[.*?\]', key) if s: s = s[0] key = key.replace(s, '') if key == 'text': if dialog.backend.name == 'win32': real = dialog.window(best_match=element).texts()[0].replace('\r\n', '\n') elif dialog.backend.name == 'uia': real = dialog.child_window(best_match=element).texts()[0].replace('\r\n', '\n') elif key == 'value': if dialog.backend.name == 'win32': real = dialog.window(best_match=element).text_block().replace('\r\n', '\n') elif dialog.backend.name == 'uia': real = dialog.child_window(best_match=element).get_value().replace('\r\n', '\n') if s: real = eval('real' + s) if key == 'selected': if dialog.backend.name == 'win32': real = dialog.window(best_match=element).is_selected() elif dialog.backend.name == 'uia': real = dialog.child_window(best_match=element).is_selected() elif key == 'checked': if dialog.backend.name == 'win32': real = dialog.window(best_match=element).is_checked() elif dialog.backend.name == 'uia': real = dialog.child_window(best_match=element).is_checked() elif key == 'enabled': if dialog.backend.name == 'win32': real = dialog.window(best_match=element).is_enabled() elif dialog.backend.name == 'uia': real = dialog.child_window(best_match=element).is_enabled() elif key == 'visible': if dialog.backend.name == 'win32': real = dialog.window(best_match=element).is_visible() elif dialog.backend.name == 'uia': real = dialog.child_window(best_match=element).is_visible() elif key == 'focused': if dialog.backend.name == 'win32': real = dialog.window(best_match=element).is_focused() elif dialog.backend.name == 'uia': real = dialog.child_window(best_match=element).is_focused() logger.info('DATA:%s' % repr(expected)) logger.info('REAL:%s' % repr(real)) compare(expected, real) # 获取元素其他属性 for key in output: k = output[key] if dialog.window(best_match=element).class_name() == 'Edit' and k == 'text': k = 'value' if k == 'text': if dialog.backend.name == 'win32': g.var[key] = dialog.window(best_match=element).texts()[0].replace('\r\n', '\n') elif dialog.backend.name == 'uia': g.var[key] = dialog.child_window(best_match=element).texts()[0].replace('\r\n', '\n') if k == 'value': if dialog.backend.name == 'win32': g.var[key] = dialog.window(best_match=element).text_block().replace('\r\n', '\n') elif dialog.backend.name == 'uia': g.var[key] = dialog.child_window(best_match=element).get_value().replace('\r\n', '\n')
def run(self): # 当前测试用例 current = {'result': 'Pass'} # 上一个测试用例 previous = {} # 1.执行用例 for testcase in self.testsuite: # 根据筛选条件,把不需要执行的测试用例跳过 flag = False for k, v in self.conditions.items(): if not isinstance(v, list): v = [v] if testcase[k] not in v: testcase['result'] = '-' flag = True if flag: continue # xml 测试报告-测试用例初始化 if testcase['flag'] != 'N': case = self.report.create_case(testcase['title'], testcase['id']) case.start() case.priority = testcase['priority'] # 用例上下文, previous = current current = testcase else: testcase['result'] = 'Skip' # case.skip('Skip', 'Autotest Flag is N') logger.info( 'Run the testcase: %s|%s Skipped, because the flag=N or the condition=snippet' % (testcase['id'], testcase['title'])) continue if testcase['condition'].lower() not in ('base', 'setup'): if testcase['condition'].lower() == 'sub': if previous['result'] != 'Pass': testcase['result'] = 'Block' case.block('Blocked', 'Main or pre Sub testcase is not pass') logger.warn( 'Run the testcase: %s|%s Blocked, Main or pre Sub TestCase is not Pass' % (testcase['id'], testcase['title'])) continue # 如果前置条件为 skip,则此用例不执行前置条件 elif testcase['condition'].lower() == 'skip': pass else: result = self.setup(testcase, case) #if result == 'N': if not result: continue try: tc = TestCase(testcase) tc.run() if testcase['result'] == 'Pass': case.succeed() elif testcase['result'] == 'Fail': case.fail('Fail', testcase['report']) if testcase['condition'].lower() == 'base': logger.warn( 'Run the testcase: %s|%s Fail, BASE is not Pass. Break the AutoTest' % (testcase['id'], testcase['title'])) break if testcase['condition'].lower() == 'setup': logger.warn( 'Run the testcase: %s|%s Fail, SETUP is not Pass. Break the AutoTest' % (testcase['id'], testcase['title'])) break
'Run the testcase: %s|%s Fail, SETUP is not Pass. Break the AutoTest' % (testcase['id'], testcase['title'])) break except Exception as exception: case.error( 'Error', 'Remark:%s |||Exception:%s' % (testcase['remark'], exception)) logger.exception('Run the testcase: %s|%s fail' % (testcase['id'], testcase['title'])) if testcase['condition'].lower() == 'base': logger.warn( 'Run the testcase: %s|%s Error, BASE is not Pass. Break the AutoTest' % (testcase['id'], testcase['title'])) break if testcase['condition'].lower() == 'setup': logger.warn( 'Run the testcase: %s|%s Error, SETUP is not Pass. Break the AutoTest' % (testcase['id'], testcase['title'])) break self.report.finish() # 2.清理环境 try: if g.platform.lower() in ('desktop', ): w.close() g.driver.quit() logger.info('--- Quit th Driver: %s' % g.browserName) except: logger.exception('Clear the env is fail')
def request(kw, step): element = step['element'] url = e.get(element)[1] if url.startswith('/'): url = url[1:] data = step['data'] # 测试数据解析时,会默认添加一个 text 键,需要删除 if 'text' in data and not data['text']: data.pop('text') _data = {} _data['headers'] = json2dict(data.pop('headers', '{}')) if data.get('cookies'): data['cookies'] = json2dict(data['cookies']) if kw == 'get': _data['params'] = json2dict(data.pop('params', '{}')) or json2dict( data.pop('data', '{}')) elif kw == 'post': if data.get('text'): _data['data'] = data.pop('text') else: _data['data'] = json2dict(data.pop('data', '{}')) _data['json'] = json2dict(data.pop('json', '{}')) _data['files'] = eval(data.pop('files', 'None')) elif kw in ('put', 'patch'): _data['data'] = json2dict(data.pop('data', '{}')) for k in data: for s in ('{', '[', 'False', 'True'): if s in data[k]: try: data[k] = eval(data[k]) except: logger.warning('Try eval data failure: %s' % data[k]) break expected = step['expected'] expected['status_code'] = expected.get('status_code', None) expected['text'] = expected.get('text', None) expected['json'] = json2dict(expected.get('json', '{}')) expected['cookies'] = json2dict(expected.get('cookies', '{}')) expected['headers'] = json2dict(expected.get('headers', '{}')) timeout = float(expected.get('timeout', 10)) expected['time'] = float(expected.get('time', 0)) if not g.http.get(step['page']): g.http[step['page']] = Http(step) http = g.http[step['page']] if kw == 'post': if http.headers_post: http.r.headers.update(eval(http.headers_post)) else: if http.headers_get: http.r.headers.update(eval(http.headers_get)) logger.info('URL: %s' % http.baseurl + url) # 处理 before_send before_send = data.pop('before_send', '') if before_send: _data, data = getattr(http_handle, before_send)(kw, _data, data) else: _data, data = getattr(http_handle, 'before_send')(kw, _data, data) if _data['headers']: for k in [x for x in _data['headers']]: if not _data['headers'][k]: del http.r.headers[k] del _data['headers'][k] http.r.headers.update(_data['headers']) if kw == 'get': r = getattr(http.r, kw)(http.baseurl + url, params=_data['params'], timeout=timeout, **data) if _data['params']: logger.info(f'PARAMS: {_data["params"]}') elif kw == 'post': r = getattr(http.r, kw)(http.baseurl + url, data=_data['data'], json=_data['json'], files=_data['files'], timeout=timeout, **data) logger.info(f'BODY: {r.request.body}') elif kw in ('put', 'patch'): r = getattr(http.r, kw)(http.baseurl + url, data=_data['data'], timeout=timeout, **data) logger.info(f'BODY: {r.request.body}') elif kw in ('delete', 'options'): r = getattr(http.r, kw)(http.baseurl + url, timeout=timeout, **data) logger.info('status_code: %s' % repr(r.status_code)) try: # json 响应 logger.info('response json: %s' % repr(r.json())) except: # 其他响应 logger.info('response text: %s' % repr(r.text)) response = { 'status_code': r.status_code, 'headers': r.headers, '_cookies': r.cookies, 'content': r.content, 'text': r.text } try: response['cookies'] = requests.utils.dict_from_cookiejar(r.cookies) except: response['cookies'] = r.cookies try: j = r.json() response['json'] = j except: response['json'] = {} # 处理 after_receive after_receive = expected.pop('after_receive', '') if after_receive: response = getattr(http_handle, after_receive)(response) else: response = getattr(http_handle, 'after_receive')(response) var = {} # 存储所有输出变量 if expected['status_code']: if str(expected['status_code']) != str(response['status_code']): raise Exception( f'status_code | EXPECTED:{repr(expected["status_code"])}, REAL:{repr(response["status_code"])}' ) if expected['text']: if expected['text'].startswith('*'): if expected['text'][1:] not in response['text']: raise Exception( f'text | EXPECTED:{repr(expected["text"])}, REAL:{repr(response["text"])}' ) else: if expected['text'] == response['text']: raise Exception( f'text | EXPECTED:{repr(expected["text"])}, REAL:{repr(response["text"])}' ) if expected['headers']: result = check(expected['headers'], response['headers']) logger.info('headers check result: %s' % result) if result['code'] != 0: raise Exception( f'headers | EXPECTED:{repr(expected["headers"])}, REAL:{repr(response["headers"])}, RESULT: {result}' ) elif result['var']: var = dict(var, **result['var']) g.var = dict(g.var, **result['var']) logger.info('headers var: %s' % (repr(result['var']))) if expected['cookies']: logger.info('response cookies: %s' % response['cookies']) result = check(expected['cookies'], response['cookies']) logger.info('cookies check result: %s' % result) if result['code'] != 0: raise Exception( f'cookies | EXPECTED:{repr(expected["cookies"])}, REAL:{repr(response["cookies"])}, RESULT: {result}' ) elif result['var']: var = dict(var, **result['var']) g.var = dict(g.var, **result['var']) logger.info('cookies var: %s' % (repr(result['var']))) if expected['json']: result = check(expected['json'], response['json']) logger.info('json check result: %s' % result) if result['code'] != 0: raise Exception( f'json | EXPECTED:{repr(expected["json"])}, REAL:{repr(response["json"])}, RESULT: {result}' ) elif result['var']: var = dict(var, **result['var']) g.var = dict(g.var, **result['var']) logger.info('json var: %s' % (repr(result['var']))) if expected['time']: if expected['time'] < r.elapsed.total_seconds(): raise Exception( f'time | EXPECTED:{repr(expected["time"])}, REAL:{repr(r.elapsed.total_seconds())}' ) output = step['output'] # if output: # logger.info('output: %s' % repr(output)) for k, v in output.items(): if v == 'status_code': g.var[k] = response['status_code'] logger.info('%s: %s' % (k, repr(g.var[k]))) elif v == 'text': g.var[k] = response['text'] logger.info('%s: %s' % (k, repr(g.var[k]))) elif k == 'json': sub = json2dict(output.get('json', '{}')) result = check(sub, response['json']) # logger.info('Compare json result: %s' % result) var = dict(var, **result['var']) g.var = dict(g.var, **result['var']) logger.info('json var: %s' % (repr(result['var']))) elif k == 'cookies': sub = json2dict(output.get('cookies', '{}')) result = check(sub, response['cookies']) # logger.info('Compare json result: %s' % result) var = dict(var, **result['var']) g.var = dict(g.var, **result['var']) logger.info('cookies var: %s' % (repr(result['var']))) if var: step['_output'] += '\n||output=' + str(var)