Xmind2Testcase增加Xmind-zen及Excel支持
安装Xmind2Testcase
下载软件
GitHub - zhuifengshen/xmind2testcase: XMind2TestCase基于python实现,提供了一个高效测试用例设计的解决方案!
git clone https://github.com/zhuifengshen/xmind2testcase.git
pip install xmind2testcase
调整目录结构
喜欢原始目录的可以忽略,不用调整
将webtool目录移动至项目根目录,如下图所示
pip uninstall xmind2testcase卸载该库
调整完后启动项目命令python application.py
注意: 以上修改会导致xmind2testcase 命令无法使用
增加Excel支持
安装软件
pip install openpyxl
修改源文件
application.py 修改有注释的地方
# 可以不修改这个,个人习惯看到了就改
# global variable
# UPLOAD_FOLDER = os.path.join(here, 'uploads')
UPLOAD_FOLDER = Path(__file__).parent / 'uploads'
def delete_record(filename, record_id):
xmind_file = app.config['UPLOAD_FOLDER'] / filename
testlink_file = app.config['UPLOAD_FOLDER'] / filename.replace("xmind", "xml")
zentao_file = app.config['UPLOAD_FOLDER'] / filename.replace("xmind", "csv")
zentao_file_excel = app.config["UPLOAD_FOLDER"] / filename.replace("xmind", "xlsx") # 此处修改,增加删除excle文件
for f in [xmind_file, testlink_file, zentao_file, zentao_file_excel]: # 此处修改,增加删除excle文件
def delete_records(keep=20):
"""Clean up files on server and mark the record as deleted"""
sql = "SELECT * from records where is_deleted<>1 ORDER BY id desc LIMIT -1 offset {}".format(keep)
assert isinstance(g.db, sqlite3.Connection)
c = g.db.cursor()
c.execute(sql)
rows = c.fetchall()
for row in rows:
name = row[1]
xmind_file = app.config['UPLOAD_FOLDER'] / name
testlink_file = app.config['UPLOAD_FOLDER'] / name.replace("xmind", "xml")
zentao_file = app.config['UPLOAD_FOLDER'] / name.replace("xmind", "csv")
zentao_file_excel = app.config["UPLOAD_FOLDER"] / name.replace("xmind", "xlsx") # 此处修改,增加删除excle文件
for f in [xmind_file, testlink_file, zentao_file, zentao_file_excel]: # 此处修改,增加删除excle文件
zentao.py 文件增加方法
def xmind_to_zento_excel_file(xmind_file):
"""
写入excle文件xlsx
"""
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 = ["所属模块", "用例标题", "前置条件", "步骤", "预期", "关键词", "优先级", "用例类型", "适用阶段",
"相关研发需求"]
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)
logging.info('The zentao csv file already exists, return it directly: %s', zentao_file)
workbook = openpyxl.workbook.Workbook()
ws = workbook.active
line = 1
for data in zentao_testcase_rows:
for col in range(1, len(data) + 1):
ws.cell(row=line, column=col).value = data[col - 1]
line += 1
workbook.save(zentao_file)
workbook.close()
logging.info('Convert XMind file(%s) to a zentao csv file(%s) successfully!', xmind_file, zentao_file)
return zentao_file
修改index.html
<td>
<a href="{{ url_for('uploaded_file',filename=record[1]) }}">XMIND</a> |
<a href="{{ url_for('download_zentao_file',filename=record[1]) }}">CSV</a> |
<a href="{{ url_for('download_testlink_file',filename=record[1]) }}">XML</a> |
<a href="{{ url_for('preview_file',filename=record[1]) }}">PREVIEW</a> |
<a href="{{ url_for('download_zentao_excel_file', filename=record[1]) }}">EXCEL</a> |{# 此处修改!!!#}
<a href="{{ url_for('delete_file',filename=record[1], record_id=record[4]) }}">DELETE</a>
</td>
修改preview.html
<h2>TestSuites: {{ suite_count }} / TestCases: {{ suite | length }}
/ <a href="{{ url_for("download_zentao_file",filename= name) }}">Get Zentao CSV</a>
/ <a href="{{ url_for("download_testlink_file",filename= name) }}">Get TestLink XML</a>
/ <a href="{{ url_for("download_zentao_excel_file",filename= name) }}">Get Zentao XLSX</a> {# 此处修改!!!#}
/ <a href="{{ url_for("index") }}">Go Back</a></h2>
增加Xmind-zen支持
安装软件
pip install xmindparser
修改源文件
修改utils.py
def get_xmind_testsuites(xmind_file):
"""Load the XMind file and parse to `xmind2testcase.metadata.TestSuite` list"""
xmind_file = get_absolute_path(xmind_file)
# 增加xmind2022支持
if is_xmind_zen(xmind_file):
xmind_content_dict = xmind_to_dict(xmind_file)
else:
workbook = xmind.load(xmind_file)
xmind_content_dict = workbook.getData()
修改zenreader.py,直接全部覆盖
注意zenreader.py文件路径在Lib\site-packages\xmindparser\zenreader.py
也可以直接把xmindparser文件夹拷贝到你项目下
如果遇到某些标记或者不支持的问题可以修改zenreader做适配
import json
from zipfile import ZipFile
from . import config, cache
content_json = "content.json"
def open_xmind(file_path):
"""open xmind as zip file and cache the content."""
cache.clear()
with ZipFile(file_path) as xmind:
for f in xmind.namelist():
for key in [content_json]:
if f == key:
cache[key] = xmind.open(f).read().decode('utf-8')
def get_sheets():
"""get all sheet as generator and yield."""
for sheet in json.loads(cache[content_json]):
yield sheet
def sheet_to_dict(sheet):
"""convert a sheet to dict type."""
topic = sheet['rootTopic']
result = {'title': sheet['title'], 'topic': node_to_dict(topic), 'structure': get_sheet_structure(sheet)}
if config['showTopicId']:
result['id'] = sheet['id']
if config['hideEmptyValue']:
result = {k: v for k, v in result.items() if v}
return result
def get_sheet_structure(sheet):
root_topic = sheet['rootTopic']
return root_topic.get('structureClass', None)
def node_to_dict(node):
"""parse Element to dict data type."""
child = children_topics_of(node)
d = {
'id': '',
'title': node.get('title', ''),
'note': note_of(node),
'markers': maker_of(node),
'label': labels_of(node),
'link': link_of(node),
'image': image_of(node),
'comment': None
# 'callout': callout_of(node)
}
if d['link']:
if d['link'].startswith('xmind'):
d['link'] = '[To another xmind topic!]'
if d['link'].startswith('xap:attachments'):
del d['link']
d['title'] = '[Attachment]{0}'.format(d['title'])
if child:
d['topics'] = []
for c in child:
d['topics'].append(node_to_dict(c))
if config['showTopicId']:
d['id'] = node['id']
# if config['hideEmptyValue']:
# d = {k: v for k, v in d.items() if v or k == 'title'}
return d
def children_topics_of(topic_node):
children = topic_node.get('children', None)
if children:
return children.get('attached', None)
def link_of(node):
return node.get('href', None)
def image_of(node):
return node.get('image', None)
def labels_of(node):
return node.get('labels', None)
def note_of(node):
note_node = node.get('notes', None)
if note_node:
note = note_node.get('plain', None)
if note:
return note.get('content', '').strip()
def maker_of(topic_node):
makers = []
maker_node = topic_node.get('markers', None)
if maker_node is not None:
for maker in maker_node:
makers.append(maker.get('markerId', None))
return makers
def callout_of(topic_node):
callout = topic_node.get('children', None)
if callout:
callout = callout.get('callout', None)
if callout:
return [x['title'] for x in callout]
运行
python application.py
致谢
https://github.com/zhuifengshen/xmind2testcase