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 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 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 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 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('data') / (g.plan_name + '-' + sheet_name + '.csv') if data_file.is_file(): g.var = get_record(str(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, sheet_name, 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 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'] if by in ('title', 'current_url'): 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)) compare(expected, real) # 获取元素其他属性 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 message(step): data = step['data'] text = data.get('text', '') element = step['element'] value = e.get(element)[1] 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 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'): 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 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 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: # 成功定位到关键元素 element_location = 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 Exception as exception: pass if not flag: raise Exception( 'Tab Name Fail: the element:%s in all tab is not found' % 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 rill_framework.testcase import elements_format from rill_framework.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 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'] == 'Pass': flag = 'Y' else: flag = 'N' else: flag = 'O' return flag setup_flag = run_setup(self.setup_testcase) if setup_flag == 'N': base_flag = run_setup(self.base_testcase) if base_flag == 'Y': setup_flag = run_setup(self.setup_testcase) if setup_flag == 'N': testcase['result'] = 'Block' case.block('Blocked', 'SETUP is not Pass') logger.warn('Run the testcase: %s|%s Blocked, SETUP is not Pass' % ( testcase['id'], testcase['title'])) return False elif base_flag == 'O': testcase['result'] = 'Block' case.block('Blocked', 'SETUP is not Pass') logger.warn('Run the testcase: %s|%s Blocked, SETUP is not Pass' % ( testcase['id'], testcase['title'])) return False return True
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 request(kw, step): element = step['element'] url = e.get(element)[1] if url.startswith('/'): url = url[1:] data = step['data'] _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': _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 fail: %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', '{}')) 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'], **data) elif kw == 'post': r = getattr(http.r, kw)(http.baseurl + url, data=_data['data'], json=_data['json'], files=_data['files'], **data) elif kw in ('put', 'patch'): r = getattr(http.r, kw)(http.baseurl + url, data=_data['data'], **data) elif kw in ('delete', 'options'): r = getattr(http.r, kw)(http.baseurl + url, **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) if expected['status_code']: assert str(expected['status_code']) == str(response['status_code']) if expected['text']: if expected['text'].startswith('*'): assert expected['text'][1:] in response['text'] else: assert expected['text'] == response['text'] if expected['headers']: result = check(expected['headers'], response['headers']) if result['result']: step['remark'] += str(result['result']) logger.info('headers check result: %s' % result) assert result['code'] == 0 if expected['cookies']: logger.info('response cookies: %s' % response['cookies']) result = check(expected['cookies'], response['cookies']) if result['result']: step['remark'] += str(result['result']) logger.info('cookies check result: %s' % result) assert result['code'] == 0 if expected['json']: result = check(expected['json'], response['json']) if result['result']: step['remark'] += str(result['result']) logger.info('json check result: %s' % result) assert result['code'] == 0 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) 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) g.var = dict(g.var, **result['var']) logger.info('cookies var: %s' %(repr(result['var'])))
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']): # 统计开始时间 step['start_timestamp'] = timestamp() # 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: after_function = step['data'].pop('AFTER_FUNCTION', '') # 变量替换 replace_dict(step['data']) replace_dict(step['expected']) step['data'].pop('BEFORE_FUNCTION', '') 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'].pop('等待时间', 0) 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() 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 if after_function: replace_dict({'after_function': after_function}) # 操作后,等待0.2秒 sleep(0.2) except Exception as exception: step['snapshot'] = file_name = g.plan_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('*** 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 # 统计结束时间 step['end_timestamp'] = timestamp() 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 run(self): self.testsuite_start() # 当前测试用例 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 # 统计开始时间 testcase['start_timestamp'] = timestamp() # 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'])) # 统计结束时间 testcase['end_timestamp'] = timestamp() 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'])) # 统计结束时间 testcase['end_timestamp'] = timestamp() continue # 如果前置条件为 skip,则此用例不执行前置条件 elif testcase['condition'].lower() == 'skip': pass else: result = self.setup(testcase, case) #if result == 'N': if not result: # 统计结束时间 testcase['end_timestamp'] = timestamp() continue try: tc = TestCase(testcase) tc.run() # 统计结束时间 testcase['end_timestamp'] = timestamp() 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
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 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') self.testsuite_end()