def __init__(self, file_name, sheet_name, desired_caps={}, server_url=''): if desired_caps: self.desired_caps = desired_caps else: self.desired_caps = { 'platformName': 'Desktop', 'browserName': 'Chrome'} self.server_url = server_url self.conditions = {} g.plan_name = file_name.split('-')[0] g.init(self.desired_caps, self.server_url) log_path = Path('snapshot') / g.plan_name / g.start_time[1:] for p in ('JUnit', 'report', 'snapshot', log_path, 'report/' + g.plan_name): mkdir(p) g.plan_data['log'] = set_log(logger, log_path) self.testcase_file = str( Path('testcase') / (file_name + '-' + _testcase + '.xlsx')) self.elements_file = str( Path('element') / (g.plan_name + '-' + _elements + '.xlsx')) self.report_xml = str( Path('JUnit') / (file_name + '-' + _report + g.start_time + '.xml')) self.testcase_workbook = Excel(self.testcase_file, 'r') self.sheet_names = self.testcase_workbook.get_sheet(sheet_name) self.report_excel = str(Path( 'report') / g.plan_name / (file_name + '-' + _report + g.start_time + '.xlsx')) self.report_workbook = Excel(self.report_excel, 'w') self.report_data = {} # 测试报告详细数据
def __init__(self, file_name, sheet_name, desired_caps={}, server_url=''): g.start_time = time.strftime("@%Y%m%d_%H%M%S", time.localtime()) if desired_caps: self.desired_caps = desired_caps else: self.desired_caps = { 'platformName': 'Desktop', 'browserName': 'Chrome' } self.server_url = server_url self.conditions = {} for p in ('JUnit', 'report', 'snapshot'): mkdir(p) g.project_name = file_name.split('-')[0] self.testcase_file = Path('testcase') / (file_name + '-' + _testcase + '.xlsx') self.elements_file = Path('element') / (g.project_name + '-' + _elements + '.xlsx') self.report_xml = Path('JUnit') / (file_name + '-' + _report + g.start_time + '.xml') self.testcase_workbook = Excel(self.testcase_file, 'r') self.sheet_names = self.testcase_workbook.get_sheet(sheet_name) self.report_workbook = Excel( Path('report') / (file_name + '-' + _report + g.start_time + '.xlsx'), 'w') self.report_data = {} # 测试报告详细数据
def __init__(self): snapshot_plan = Path('snapshot') / g.plan_name self.snapshot_folder = snapshot_plan / g.start_time[1:] snapshot_expected = Path('snapshot') / 'expected' self.expected_folder = snapshot_expected / g.plan_name for p in (snapshot_plan, self.snapshot_folder, snapshot_expected, self.expected_folder): mkdir(p)
def set_log(logger, log_path): mkdir('log') # 文件日志 log_file = Path('log') / f'{today()}.log' file_handler = logging.FileHandler(filename=log_file, encoding="utf-8") file_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式 # 单次文件日志 sweet_log = log_path / 'sweet.log' try: sweet_log.unlink() except: pass sweet_handler = logging.FileHandler(filename=sweet_log, encoding="utf-8") sweet_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式 # 控制台日志 console_handler = logging.StreamHandler(sys.stdout) console_handler.formatter = formatter # 也可以直接给formatter赋值 # 为logger添加的日志处理器 logger.addHandler(file_handler) logger.addHandler(sweet_handler) logger.addHandler(console_handler) # 指定日志的最低输出级别,默认为WARN级别 # DEBUG,INFO,WARNING,ERROR,CRITICAL logger.setLevel(logging.INFO) return str(sweet_log)
def set_log(logger): mkdir('log') # 文件日志 log_file = Path('log') / f'{today()}.log' file_handler = logging.FileHandler(filename=log_file, encoding="utf-8") file_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式 # 控制台日志 console_handler = logging.StreamHandler(sys.stdout) console_handler.formatter = formatter # 也可以直接给formatter赋值 # 为logger添加的日志处理器 logger.addHandler(file_handler) logger.addHandler(console_handler) # 指定日志的最低输出级别,默认为WARN级别 # DEBUG,INFO,WARNING,ERROR,CRITICAL logger.setLevel(logging.INFO)
import sys from sweetest.utility import mkdir def today(): now = datetime.datetime.now() return now.strftime('%Y%m%d') # 获取logger实例,如果参数为空则返回root logger logger = logging.getLogger("sweetest") # 指定logger输出格式 formatter = logging.Formatter('%(asctime)s [%(levelname)s]: # %(message)s') mkdir('log') # 文件日志 log_file = Path('log') / f'{today()}.log' file_handler = logging.FileHandler(filename=log_file, encoding="utf-8") file_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式 # 控制台日志 console_handler = logging.StreamHandler(sys.stdout) console_handler.formatter = formatter # 也可以直接给formatter赋值 # 为logger添加的日志处理器 logger.addHandler(file_handler) logger.addHandler(console_handler) # 指定日志的最低输出级别,默认为WARN级别 # DEBUG,INFO,WARNING,ERROR,CRITICAL
def markdown(plan, testsuites, testcases, md_path='markdown'): success = OK = '<font color=#00BB00>通过</font>' failure = NO = '<font color=#FF0000>失败</font>' blocked = '<font color=#FFD306>阻塞</font>' skipped = '<font color=#6C6C6C>-</font>' md = '| 测试套件名称 | 开始时间 | 结束时间 | 耗时 | 成功个数 | 失败个数 | 阻塞个数 | 总个数 | 结果 |\n' md += '| ----------- | ------- | ------- | ---- | ------- | ------- | -------- | ----- | ---- |\n' result = success sc, fc, bc, tc = 0, 0, 0, 0 for v in testsuites.values(): sc += v['success'] fc += v['failure'] bc += v['blocked'] tc += v['total'] re = success if v['result'] == 'failure': re = failure cost = round((v['end_timestamp'] - v['start_timestamp']) / 1000, 1) md += f'| {v["testsuite"]} | {tm(v["start_timestamp"])} | {tm(v["end_timestamp"])} | {cost} | ' md += f'{v["success"]} | {v["failure"]} | {v["blocked"]} | {v["total"]} | {re} |\n' if v['result'] == 'failure': result = failure cost = round((plan['end_timestamp'] - plan['start_timestamp']) / 1000, 1) md += f'| **共计** | {tm(plan["start_timestamp"])} | {tm(plan["end_timestamp"])} | {cost} | ' md += f'{sc} | {fc} | {bc} | {tc} | {result} |\n' title = f'# 「{plan["plan"]}」自动化测试执行报告 {result} #\n\n[历史记录](/{plan["plan"]}/)\n\n' md = title + f'## 测试计划执行结果\n\n{md}\n\n## 测试套件执行结果\n\n' if result == success: icon = '✔️' else: icon = '❌' message = f'- {icon} <font color=#9D9D9D size=2>{tm(plan["start_timestamp"])} - {tm(plan["end_timestamp"])}</font> 测试计划' message += f'「[{plan["plan"]}]({plan["plan"]}/{plan["plan"]}_{tm(plan["start_timestamp"], "_")})」执行完成,测试结果:{result},成功:{sc},失败:{fc},阻塞:{bc}\n\n' # 测试套件 - 测试用例结果 txt = '' for k, v in testcases.items(): txt += f'\n- ### {k}\n\n' txt += '| 用例id | 用例名称 | 前置条件 |开始时间 | 结束时间 | 耗时 | 结果 |\n' txt += '| ------- | ------- | ----------- | -------------- | -------------- | ----- | ------- |\n' for case in v: if case['flag'] == 'N': continue cost = round( (case['end_timestamp'] - case['start_timestamp']) / 1000, 1) result = eval(case['result']) txt += f'| [{case["id"]}](#{case["id"]}) | {case["title"]} | {case["condition"]} | {tm(case["start_timestamp"])} | {tm(case["end_timestamp"])} | {cost} | {result} |\n' md += f'{txt}\n\n## 测试用例执行结果\n' txt = '' for k, v in testcases.items(): txt += f'\n- ### {k}\n' for case in v: if case['flag'] == 'N': continue txt += f'\n#### {case["id"]}\n\n**{case["title"]}** | {case["condition"]} | {case["designer"]} | {eval(case["result"])}\n\n' txt += '| 步骤 | 操作 | 页面 | 元素 | 测试数据 | 预期结果 | 输出数据 | 耗时 | 测试结果 | 备注 | 截图 |\n' txt += '|------|-------|-------|------|-----------|---------|-----------|-----|---------|------|--------|\n' for step in case['steps']: cost = round((step.get('end_timestamp', 0) - step.get('start_timestamp', 0)) / 1000, 1) if cost == 0: cost = '-' if not step['score']: result = skipped else: result = eval(step['score']) snapshot = '' if 'snapshot' in step: for k, v in step['snapshot'].items(): snapshot += f"[{k}](/report/{v} ':ignore')\n" txt += f'| {step["no"]} | {step["keyword"]} | {step["page"]} | {escape(step["element"])} | {escape(step["data"])} | {escape(step["expected"])} | {escape(step["output"])} | {cost} | {result} | {step["remark"]} | {escape(snapshot, "%23")} |\n' result = eval(case['result']) md += txt p = Path(md_path) / 'report' latest = p / 'latest' report = p / g.plan_name mkdir(p) mkdir(report) with open(p / 'README.md', 'r', encoding='UTF-8') as f: txt = f.read() if '恭喜你安装成功' in txt: txt = '' with open(p / f'README.md', 'w', encoding='UTF-8') as f: f.write(message + txt) with open(latest / f'{g.plan_name}.md', 'w', encoding='UTF-8') as f: f.write(md) readme = report / 'README.md' if readme.is_file(): with open(report / 'README.md', 'r', encoding='UTF-8') as f: txt = f.read() else: txt = '' with open(report / 'README.md', 'w', encoding='UTF-8') as f: f.write(message + txt) with open(report / f'{plan["plan"]}_{tm(plan["start_timestamp"], "_")}.md', 'w', encoding='UTF-8') as f: f.write(md) with open(p / '_sidebar.md', 'r', encoding='UTF-8') as f: txt = f.read() if f'[{g.plan_name}]' not in txt: with open(p / '_sidebar.md', 'a', encoding='UTF-8') as f: f.write(f'\n * [{g.plan_name}](latest/{g.plan_name})') files = [] for f in report.iterdir(): if f.stem not in ['_sidebar', 'README']: files.append(f.stem) files.sort(reverse=True) with open(report / '_sidebar.md', 'w', encoding='UTF-8') as f: txt = f'* 「{g.plan_name}」测试结果\n' for stem in files: txt += f'\n * [{stem}]({g.plan_name}/{stem})' f.write(txt)
def __init__(self): self.plan_folder = 'snapshot/' + g.plan_name self.snapshot_folder = self.plan_folder + '/' + g.start_time[1:] self.expected_folder = 'snapshot/expected/' + g.plan_name for p in (self.plan_folder, self.snapshot_folder, self.expected_folder): mkdir(p)