【测试效率提升技巧】xmind测试用例转换为excel工具使用手册

【测试效率提升技巧】xmind测试用例转换为excel工具使用手册

    • 一、前置环境配置
    • 二、执行
      • Xmind2testcase的转换方法
        • 1.在控制台输入xmind2testcase [path/xmind文件路径] [-csv] [-xml] [-json],例:xmind2testcase /root/homin/XX测试点.xmind -csv ##在当前目录下会转换为对应的csv类型文件。
        • 2.在控制台输入 xmind2testcase webtool 8000 ,定义好本地端口后访问http://127.0.0.1:8000/,可通过web端进行文件转换,之后可通过点击“Get Zentao CSV / Get TestLink XML / Go Back”,生成对应的文件类型。
    • 三、xmind书写模板和规则
    • 四.xmind2testcase转换库针对禅道代码改良
      • 4.1修改优先级,修改zentao.py
      • 4.2.修改用例类型,修改zentao.py
      • 4.3.修改适应阶段,修改zentao.py
      • 4.4.导出文件有空行,修改zentao.py
      • 4.5.用例步骤、预期结果序号后多一个空格,修改zentao.py
      • 4.6.每导出一个用例步骤和预期结果都会多一个换行符,修改zentao.py
      • 4.7.填写默认关键词,修改zentao.py
      • 4.8.去掉用例标题中的空格,修改parser.py
      • 4.9.增加需求字段
        • 4.9.1修改metadata.py
        • 4.9.2 修改utils.py
      • 4.10.把原先的产品名(中心主题)改为功能模块名,输出文件名字一致,修改parser.py
    • 五.修改xmind2testcase支持导出xlsx文档
      • 5.1 使用pandas库
        • 5.1.1在zentao.py文件中添加函数:xmind_to_zentao_xlsx_file_by_pandas,如下:
        • 5.1.2在application.py中添加路由
        • 5.1.3在index.html添加xlsx的访问路径
        • 5.1.4在ipreview.html添加xlsx的访问路径
      • 5.2 使用openpyxl
    • 六.编写规则

一、前置环境配置

1.在命令行执行pip install xmind2testcase -U
2.到python中xmind2testcase的安装路径(我的路径是D:\python\Lib\site-packages\xmind2testcase)下新建一个文件夹,命名为web
3.在命令行cd到刚刚创建的web文件夹,执行pip freeze > requirements.txt
4.命令行执行pip install -r requirements.txt -U

PS:请尽量使用xMind8 Update9版本编写测试用例,否则可能出现无法转换的情况

二、执行

运行python安装目录下的application.py文件(我的文件位置在D:\python\Lib\site-packages\webtool\application.py)
命令行会显示本地生成的网页网址,直接复制到浏览器进入即可
在这里插入图片描述
实现效果如下:
在这里插入图片描述

Xmind2testcase的转换方法

1.在控制台输入xmind2testcase [path/xmind文件路径] [-csv] [-xml] [-json],例:xmind2testcase /root/homin/XX测试点.xmind -csv ##在当前目录下会转换为对应的csv类型文件。

2.在控制台输入 xmind2testcase webtool 8000 ,定义好本地端口后访问http://127.0.0.1:8000/,可通过web端进行文件转换,之后可通过点击“Get Zentao CSV / Get TestLink XML / Go Back”,生成对应的文件类型。

三、xmind书写模板和规则

这里是标准的xmind转换库所要求的xming用例格式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第六条规则,我们使用标注优先级图标作为”测试标题”与”测试步骤”界线,如果解析过程没有遇到优先级图标,则TestSuite后面的子主题链作为一条测试用例。
一条测试用例支持只有标题,没有测试步骤和预期结果,因为实际测试过程中,我们常常通过用例标题就可以明确测试点了。

之所以有第六条规则这样设计,因为实际测试用例设计过程中,我们所测产品往往有非常多的模块和层级。

四.xmind2testcase转换库针对禅道代码改良

默认下xmind2testcase转换的csv文件导入禅道时,不会添加用例类型和测试阶段。这里通过修改代码的方式使其导入时具有默认值,免去了导入后还要手动填写的麻烦。

4.1修改优先级,修改zentao.py

def gen_case_priority(priority):# 修改前# mapping = {1: '高', 2: '中', 3: '低'}# 修改后mapping = {1: '1', 2: '2', 3: '3', 4: '4'}if priority in mapping.keys():return mapping[priority]else:# 修改前return '中'# 修改后return '2'

4.2.修改用例类型,修改zentao.py

# 用例类型 用星星实现
def gen_case_type(case_type):mapping = {'star-red': "功能", "star-orange": "UI自动化", "star-blue": "接口自动化", "star-green": "性能","star-purple": "安全", "star-dark-green": "安装部署", "star-dark-gray": "其他"}if case_type in mapping.keys():return mapping[case_type]else:return '功能'

4.3.修改适应阶段,修改zentao.py

def gen_a_testcase_row(testcase_dict):# ['所属模块', '相关需求', '用例标题', '前置条件', '步骤', '预期', '关键词', '优先级', '用例类型', '适用阶段']case_module = gen_case_module(testcase_dict['suite'])case_demand_name = gen_case_demand_name(testcase_dict['demand_name'])case_title = testcase_dict['name']case_precontion = testcase_dict['preconditions']  # 前置条件case_step, case_expected_result = gen_case_step_and_expected_result(testcase_dict['steps'])  # 测试步骤和预期case_keyword = gen_case_keyword(testcase_dict['demand_name'])  #关键词case_priority = gen_case_priority(testcase_dict['importance'])case_type = gen_case_type(testcase_dict['execution_type'])  # 用例类型 默认功能 标签实现# 修改前# case_apply_phase = '迭代测试'# 修改后case_apply_phase = '功能测试阶段'row = [case_module, case_demand_name, case_title, case_precontion, case_step, case_expected_result, case_keyword,case_priority, case_type, case_apply_phase]return row

4.4.导出文件有空行,修改zentao.py

zentao.py文件找到xmind_to_zentao_csv_file函数,写入文件方法加上newline=''
# 修改前
# with open(zentao_file, 'w', encoding='utf8') as f:
# 修改后
with open(zentao_file, 'w', encoding='utf8', newline='') as f:

4.5.用例步骤、预期结果序号后多一个空格,修改zentao.py

def gen_case_step_and_expected_result(steps):case_step = ''case_expected_result = ''# 修改后,把+ '. ' + 后的空格去掉  + '.' +for step_dict in steps:case_step += str(step_dict['step_number']) + '.' + step_dict['actions'].replace('\n', '').strip() + '\n'case_expected_result += str(step_dict['step_number']) + '.' + \step_dict['expectedresults'].replace('\n', '').strip() + '\n' \

4.6.每导出一个用例步骤和预期结果都会多一个换行符,修改zentao.py

在这里插入图片描述
需要去除最后一个换行符

def gen_case_step_and_expected_result(steps):case_step = ''case_expected_result = ''# 修改后,把+ '. ' + 后的空格去掉  + '.' +for step_dict in steps:case_step += str(step_dict['step_number']) + '.' + step_dict['actions'].replace('\n', '').strip() + '\n'case_expected_result += str(step_dict['step_number']) + '.' + \step_dict['expectedresults'].replace('\n', '').strip() + '\n' \if step_dict.get('expectedresults', '') else ''# 添加,去除每个单元格里最后一个换行符case_step = case_step.rstrip('\n')case_expected_result = case_expected_result.rstrip('\n')return case_step, case_expected_result

4.7.填写默认关键词,修改zentao.py

def gen_a_testcase_row(testcase_dict):case_module = gen_case_module(testcase_dict['suite'])case_title = testcase_dict['name']case_precontion = testcase_dict['preconditions']case_step, case_expected_result = gen_case_step_and_expected_result(testcase_dict['steps'])# 此处可填写默认关键词case_keyword = ''

4.8.去掉用例标题中的空格,修改parser.py

def gen_testcase_title(topics):"""Link all topic's title as testcase title"""titles = [topic['title'] for topic in topics]titles = filter_empty_or_ignore_element(titles)# when separator is not blank, will add space around separator, e.g. '/' will be changed to ' / 'separator = config['sep']if separator != ' ':# 修改前# separator = ' {} '.format(separator)# 修改后separator = ' {} '.format(separator)return separator.join(titles)

4.9.增加需求字段

4.9.1修改metadata.py

    def __init__(self, name='', demand_name='', details='', testcase_list=None, sub_suites=None, statistics=None):"""TestSuite:param name: test suite name 模块名:param name: test suite demand_name 需求名:param details: test suite detail infomation:param testcase_list: test case list:param sub_suites: sub test suite list:param statistics: testsuite statistics info {'case_num': 0, 'non_execution': 0, 'pass': 0, 'failed': 0, 'blocked': 0, 'skipped': 0}"""self.name = nameself.demand_name = demand_nameself.details = detailsself.testcase_list = testcase_listself.sub_suites = sub_suitesself.statistics = statisticsdef to_dict(self):data = {'name': self.name,'demand_name': self.demand_name,'details': self.details,'testcase_list': [],'sub_suites': []}        

4.9.2 修改utils.py

def get_xmind_testcase_list(xmind_file):"""Load the XMind file and get all testcase in it:param xmind_file: the target XMind file:return: a list of testcase data"""xmind_file = get_absolute_path(xmind_file)testsuites = get_xmind_testsuites(xmind_file)testcases = []for testsuite in testsuites:product = testsuite.namefor suite in testsuite.sub_suites:for case in suite.testcase_list:case_data = case.to_dict()case_data['product'] = productcase_data['suite'] = suite.namecase_data['demand_name'] = suite.demand_nametestcases.append(case_data)return testcases

4.10.把原先的产品名(中心主题)改为功能模块名,输出文件名字一致,修改parser.py

def xmind_to_testsuites(xmind_content_dict):"""convert xmind file to `xmind2testcase.metadata.TestSuite` list"""suites = []for sheet in xmind_content_dict:root_topic = sheet['topic']for i in range(len(root_topic['topics'])):suite = sheet_to_suite(root_topic['topics'][i])suites.append(suite)return suitesdef filter_empty_or_ignore_element(values):"""Filter all empty or ignore XMind elements, especially notes、comments、labels element"""result = []for value in values:if isinstance(value, str) and not value.strip() == '' and not value[0] in config['ignore_char']:result.append(value.strip())return resultdef sheet_to_suite(root_topic):"""convert a xmind sheet to a `TestSuite` instance"""suite = TestSuite()root_title = []def x(data):root_title.append(data['title'])if 'topics' in data.keys():data = data['topics'][0]x(data)x(root_topic)global module_name, demand_namemodule_name = root_title[1]  # 模块名demand_name = root_title[0] # 需求名suite.name = module_name  # 模块名suite.demand_name = demand_name  # 需求名suite.details = root_topic['note']suite.sub_suites = []for suite_dict in [root_topic]:suite.sub_suites.append(parse_testsuite(suite_dict))return suitedef parse_testsuite(suite_dict):testsuite = TestSuite()testsuite.name = module_name  # 模块名testsuite.demand_name = demand_name  # 需求名testsuite.details = suite_dict['note']testsuite.testcase_list = []for cases_dict in suite_dict.get('topics', []):for case in recurse_parse_testcase(cases_dict):testsuite.testcase_list.append(case)return testsuitedef recurse_parse_testcase(case_dict, parent=None):if is_testcase_topic(case_dict):case = parse_a_testcase(case_dict, parent)yield caseelse:if not parent:parent = []parent.append(case_dict)for child_dict in case_dict.get('topics', []):for case in recurse_parse_testcase(child_dict, parent):yield caseparent.pop()def is_testcase_topic(case_dict):"""A topic with a priority marker, or no subtopic, indicates that it is a testcase"""priority = get_priority(case_dict)if priority:return Truechildren = case_dict.get('topics', [])if children:return Falsereturn True# 用例数据组合
def parse_a_testcase(case_dict, parent):testcase = TestCase()topics = parent + [case_dict] if parent else [case_dict]# 用例名称testcase.name = gen_testcase_title(topics)# 前置条件preconditions = gen_testcase_preconditions(topics)testcase.preconditions = preconditions if preconditions else ' 'summary = gen_testcase_summary(topics)testcase.summary = summary if summary else testcase.nametestcase.execution_type = get_execution_type(case_dict)  # 用例类型testcase.importance = get_priority(case_dict) or 2  # 优先级 1 2 3 4step_dict_list = case_dict.get('topics', [])if step_dict_list:testcase.steps = parse_test_steps(step_dict_list)testcase.result = get_test_result(case_dict['markers'])if testcase.result == 0 and testcase.steps:for step in testcase.steps:if step.result == 2:testcase.result = 2breakif step.result == 3:testcase.result = 3breaktestcase.result = step.resultreturn testcase# 用例类型
def get_execution_type(case_dict):if isinstance(case_dict['markers'], list):for marker in case_dict['markers']:if marker.startswith('star'):return marker# 优先级
def get_priority(case_dict):"""Get the topic's priority(equivalent to the importance of the testcase)"""if isinstance(case_dict['markers'], list):for marker in case_dict['markers']:if marker.startswith('priority'):return int(marker[-1])# 用例名称
def gen_testcase_title(topics):"""Link all topic's title as testcase title"""titles = [topic['title'] for topic in topics]titles = filter_empty_or_ignore_element(titles)return titles[-1]# 前置条件 修改成标签
def gen_testcase_preconditions(topics):labels = [topic.get('label', '') for topic in topics]labels = filter_empty_or_ignore_element(labels)for item in labels[::-1]:return itemdef gen_testcase_summary(topics):comments = [topic['comment'] for topic in topics]comments = filter_empty_or_ignore_element(comments)return config['summary_sep'].join(comments)# 用例步骤
def parse_test_steps(step_dict_list):steps = []for step_num, step_dict in enumerate(step_dict_list, 1):test_step = parse_a_test_step(step_dict)test_step.step_number = step_numsteps.append(test_step)return steps# 预期结果
def parse_a_test_step(step_dict):test_step = TestStep()test_step.actions = step_dict['title']expected_topics = step_dict.get('topics', [])if expected_topics:# 预期结果获取expected_topic = expected_topics[0]expected_result = expected_topic['title']if expected_result is None:  # 如果预期结果为空 使用空格占位expected_result = ' 'test_step.expectedresults = expected_resultmarkers = expected_topic['markers']test_step.result = get_test_result(markers)else:markers = step_dict['markers']test_step.result = get_test_result(markers)return test_step

五.修改xmind2testcase支持导出xlsx文档

默认只能导出csv格式的,而公司用的禅道版本又只支持xlsx格式的导入

5.1 使用pandas库

5.1.1在zentao.py文件中添加函数:xmind_to_zentao_xlsx_file_by_pandas,如下:

import pandas as pd    #使用pandas包来写入excel的,需要引入
def xmind_to_zentao_xlsx_file_by_pandas(xmind_file): #xmind导出禅道用例模板的xlsx格式"""Convert XMind file to a zentao xlsx file"""xmind_file = get_absolute_path(xmind_file)logging.info('Start converting XMind file(%s) to zentao file...', xmind_file)testcases = get_xmind_testcase_list(xmind_file)fileheader = ["所属模块", "相关需求", "用例标题", "前置条件", "步骤", "预期", "关键词", "优先级", "用例类型", "适用阶段"]  # zd:添加“相关需求”字段zentao_testcase_rows = []for testcase in testcases:row = gen_a_testcase_row(testcase)zentao_testcase_rows.append(row)zentao_file = xmind_file[:-6] + '.xlsx'df = pd.DataFrame(data=zentao_testcase_rows, columns=fileheader) #构造数据df.to_excel(zentao_file, index=False)  #写入文件,设置不需要索引logging.info('Convert XMind file(%s) to a zentao csv file(%s) successfully!', xmind_file, zentao_file)return zentao_file

5.1.2在application.py中添加路由

@app.route('/<filename>/to/zentao_xlsx')
def download_zentao_xlsx_file(filename):full_path = join(app.config['UPLOAD_FOLDER'], filename)if not exists(full_path):abort(404)zentao_xlsx_file = xmind_to_zentao_xlsx_file_by_pandas(full_path)filename = os.path.basename(zentao_xlsx_file) if zentao_xlsx_file else abort(404)return send_from_directory(app.config['UPLOAD_FOLDER'], filename, as_attachment=True)

5.1.3在index.html添加xlsx的访问路径

<a href="{{ url_for('download_zentao_xlsx_file',filename=record[1]) }}">xlsx</a> |

5.1.4在ipreview.html添加xlsx的访问路径

<a href="{{ url_for('download_zentao_xlsx_file',filename= name) }}">Get Zentao xlsx</a>

运行application.py,即可看到此项目以运行,访问后则可以看到添加的xlsx导出链接
在这里插入图片描述

5.2 使用openpyxl

def xmind_to_zentao_xlsx_file(xmind_file):xmind_file = get_absolute_path(xmind_file)testcases = get_xmind_testcase_list(xmind_file)# print(testcases)fileheader = ["所属模块", "相关需求", "用例标题", "前置条件", "步骤", "预期", "关键词", "优先级", "用例类型", "适用阶段"]zentao_testcase_rows = [fileheader]for testcase in testcases:row = gen_a_testcase_row(testcase)zentao_testcase_rows.append(row)zentao_file = xmind_file[:-6] + '.xlsx'if os.path.exists(zentao_file):os.remove(zentao_file)xl = openpyxl.Workbook()xls = xl.create_sheet(index=0)for i in zentao_testcase_rows:xls.append(i)xl.save(zentao_file)return zentao_file

六.编写规则

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/9563.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于OIDC的SSO单点登录

文章目录 什么是SSO&#xff08;Single Sign On&#xff09;单点登录OIDC&#xff08;Open ID Connect&#xff09;SSO服务授权流程&#xff08;OIDC&#xff09;授权模式授权码模式授权码模式授权流程请求授权码过程 授权模式对比总结 什么是SSO&#xff08;Single Sign On&am…

MySQL数据库索引机制

文章目录 一、MySQL缓冲区二、MySQL的page1.认识单个page2.认识多个页3.聚簇索引和非聚簇索引 三、索引的操作1.创建主键索引2.创建唯一索引3.创建普通索引4.查询索引的方法5.删除索引的方法6.索引创建原则 一、MySQL缓冲区 MySQL是一款有客户端和服务端的网络应用&#xff0c…

Ubuntu学习笔记(一)——目录与路径

文章目录 前言一、相对路径与绝对路径1.绝对路径&#xff08;absolute&#xff09;2.相对路径&#xff08;relative&#xff09; 二、目录相关操作命令1.cd(change directory, 切换目录)2.pwd(print working directory, 显示目前所在的目录)3.mkdir(make directory, 建立新目录…

简单认识LVS-DR负载群集和部署实例

文章目录 一、LVS-DR负载群集简介1、DR模式数据包流向分析2、DR 模式的特点 二、DR模式 LVS负载均衡群集部署 一、LVS-DR负载群集简介 1、DR模式数据包流向分析 1、客户端发送请求到 Director Server&#xff08;负载均衡器&#xff09;&#xff0c;请求的数据报文&#xff0…

jvm自带故障处理工具之jmap

jmap是java虚拟机自带的一种内存映像工具。 一般通过jmap可以生成堆的当前使用情况的快照&#xff0c;然后用它来分析或者调优JVM内存使用。 jmap -help jmap -histo:live pid 打印堆的直方图。对于每个Java类&#xff0c;将打印对象数&#xff0c;以字节为单位的内存大小以…

【深入浅出 Spring Security(七)】RememberMe的实现原理详讲

RememberMe 的实现原理 一、RememberMe 的基本使用二、RememberMeAuthenticationFilter 源码分析RememberMeServicesTokenBasedRememberMeServicesTokenBasedRememberMeServices 中对 processAutoLoginCookie 方法的实现总结原理图式 三、提高安全性PersistentTokenBasedRememb…

MySQL安装与部署

第一种方法&#xff1a;在线安装 配置一个安装yum源 Adding the MySQL Yum Repository 可以手动配置yum源&#xff0c;baseurl指向国内镜像源地址&#xff0c;比如清华、中科大。 Installing MySQL Starting the MySQL Server&#xff1a; 查询临时登录密码 修改数据库密码…

Linux内核代码中常用的数据结构

Linux内核代码中广泛使用了数据结构和算法&#xff0c;其中最常用的两个是链表和红黑树。 链表 Linux内核代码大量使用了链表这种数据结构。链表是在解决数组不能动态扩展这个缺陷而产生的一种数据结构。链表所包含的元素可以动态创建并插入和删除。 链表的每个元素都是离散…

eBPF内核技术在滴滴云原生的落地实践

将滴滴技术设为“星标⭐️” 第一时间收到文章更新 导读 eBPF是Linux内核革命性技术&#xff0c;能够安全高效地扩展内核能力&#xff0c;应用广泛&#xff0c;尤其是在云原生可观测性领域的应用已经成为行业热点。在滴滴云原生环境中&#xff0c;eBPF技术进行了业务实践和内源…

CesiumJS使用详细,在vue中使用Cesium.js(WebGIS中的Cesium地图可视化应用)

简述&#xff1a;Cesium是一种基于WebGL开源的虚拟地球技术&#xff0c;可以用于构建高性能、跨平台的三维地球应用程序&#xff0c;它支持多种数据格式和地图服务&#xff0c;可以实现地球表面的高精度渲染、地形分析、数据可视化等功能。Cesium还提供了丰富的API和插件&#…

青岛大学_王卓老师【数据结构与算法】Week04_05_双向链表的删除_学习笔记

本文是个人学习笔记&#xff0c;素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享&#xff0c;另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权&#xff0c;请留言作删文处理。 课程视频链接&#xff1a; 数据结构与算法基础–…

2023年03月份青少年软件编程Python等级考试试卷三级真题(含答案)

2023-03 Python三级真题 分数&#xff1a;100 题数&#xff1a;38 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1.十进制数111转换成二进制数是&#xff1f;&#xff08; &#xff09;&#xff08;2分&#xff09; A.111 B.1111011 C.101111 D…