提交代码
This commit is contained in:
parent
90ff3fef8a
commit
ac8e045834
|
@ -0,0 +1,63 @@
|
|||
changes log
|
||||
======================================
|
||||
1.1.0 2021-12-13
|
||||
|
||||
修改tox和主程序名称
|
||||
|
||||
[mh]
|
||||
------------------------------
|
||||
1.1.0 2021-01-16
|
||||
|
||||
兼容py2.7
|
||||
|
||||
[mh]
|
||||
------------------------------
|
||||
1.1.0 2021-01-15
|
||||
|
||||
更改方法,pandas太庞大了,功能严重冗余,直接用xlrd来做
|
||||
|
||||
[mh]
|
||||
------------------------------
|
||||
1.0.1 2021-01-11
|
||||
|
||||
基础功能测试用例中添加子模块的注释信息
|
||||
|
||||
[mh]
|
||||
------------------------------
|
||||
1.0.1 2020-11-27
|
||||
|
||||
修改编译,支持打包
|
||||
|
||||
[mh]
|
||||
|
||||
------------------------------
|
||||
1.0.0 2020-11-05
|
||||
|
||||
1.format格式
|
||||
2.添加异常测试的实现
|
||||
3.所有预期功能全部完成
|
||||
|
||||
[mh]
|
||||
------------------------------
|
||||
0.0.1 2020-11-05
|
||||
|
||||
1.修改程序,能够处理多个文件
|
||||
2.增加多个模板,用来处理多个不同的sheet
|
||||
|
||||
[mh]
|
||||
------------------------------
|
||||
0.0.1 2020-11-02
|
||||
|
||||
1.使用pandas+jinja2来做
|
||||
2.只针对基础功能测试的sheet页,生成1个feature文件
|
||||
|
||||
[mh]
|
||||
------------------------------
|
||||
0.0.1 2020-10-28
|
||||
|
||||
1.开始规划,先调研一下怎么做
|
||||
2.提交基础框架
|
||||
|
||||
COMMON-6503 【测试用例】做个程序将Excel转为feature,方面维护
|
||||
|
||||
[mh]
|
|
@ -0,0 +1,5 @@
|
|||
include README.txt
|
||||
include requirements.txt tox.ini
|
||||
recursive-include test *.txt *.py
|
||||
recursive-include *.txt *.py *.tmpl
|
||||
recursive-include bin *.*
|
14
README.md
14
README.md
|
@ -1,3 +1,15 @@
|
|||
# excel2feature
|
||||
|
||||
将excel转换为behave的features文件
|
||||
将excel转换为behave的features文件
|
||||
|
||||
|
||||
使用方法:
|
||||
1. 安装python3.7 开发环境
|
||||
2.用tox构建环境
|
||||
tox -e devenv
|
||||
3.将修改后的excel文件放到excel_files目录中
|
||||
4.运行程序
|
||||
devenv\Scripts\activate
|
||||
python bin\e2f.py
|
||||
5.查看output目录生成的feature文件
|
||||
6.拿生成的feature放到项目中运行一下,确认生成的Excel文件符合预期
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import site
|
||||
|
||||
# set path
|
||||
py_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
parent_dir = os.path.dirname(py_dir)
|
||||
|
||||
# print parent_dir
|
||||
# if os.path.isdir(os.path.join(parent_dir, "delegate")):
|
||||
# sys.path.append(parent_dir)
|
||||
|
||||
libdir = os.path.join(parent_dir, "lib")
|
||||
# print libdir
|
||||
if os.path.isdir(libdir):
|
||||
old_len = len(sys.path)
|
||||
new_sys_path = []
|
||||
site.addsitedir(libdir) # @UndefinedVariable
|
||||
for item in sys.path[old_len:]:
|
||||
new_sys_path.append(item)
|
||||
sys.path.remove(item)
|
||||
sys.path[:0] = new_sys_path
|
||||
|
||||
# set cwd
|
||||
os.chdir(parent_dir)
|
|
@ -0,0 +1,180 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import io
|
||||
import _load
|
||||
import shutil
|
||||
import time
|
||||
import xlrd
|
||||
|
||||
from fnmatch import fnmatch
|
||||
from jinja2 import Environment, PackageLoader
|
||||
#处理py2的编码和字典顺序的问题
|
||||
#from __future__ import unicode_literals --必须放在第一个
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
class xl2fe:
|
||||
|
||||
def __init__(self):
|
||||
HERE = os.path.dirname(__file__)
|
||||
TOP = os.path.join(HERE, "..")
|
||||
self.templates_dir = os.path.join(TOP, "templates")
|
||||
self.output_dir = os.path.join(TOP, "output")
|
||||
if os.path.exists(self.output_dir):
|
||||
shutil.rmtree(self.output_dir)
|
||||
time.sleep(2)
|
||||
os.mkdir(self.output_dir)
|
||||
self.excel_files_dir = os.path.join(TOP, "excel_files")
|
||||
self.xlsx_sheets = {"封面": "00_home_index.feature",
|
||||
"统计表": "01_statistics.feature",
|
||||
"基础功能测试用例": "02_function.feature",
|
||||
"异常测试": "03_abnormality_test.feature",
|
||||
"性能测试": "04_performance.feature"
|
||||
}
|
||||
|
||||
def read_xlsx(self):
|
||||
"""
|
||||
指定的sheet页,对内容进行处理
|
||||
"""
|
||||
#获取所有的数据
|
||||
work_book = xlrd.open_workbook(self.xlsx_file_path)
|
||||
#为了让py2字典的顺序与py3一致
|
||||
all_data = OrderedDict()
|
||||
for i, sheet_obj in enumerate(work_book.sheets()):
|
||||
all_data[sheet_obj.name] = [sheet_obj.row_values(row)
|
||||
for row in range(sheet_obj.nrows)]
|
||||
#按sheet页处理
|
||||
for sheet_name, self.feature_name in self.xlsx_sheets.items():
|
||||
datas = all_data[sheet_name]
|
||||
# 处理数据
|
||||
self.context = OrderedDict()
|
||||
self.context = xl2fe.get_feature_data(self, datas, sheet_name)
|
||||
# 渲染模板
|
||||
xl2fe.feature_tpl(self)
|
||||
|
||||
def get_feature_data(self, datas, sheet_name):
|
||||
"""
|
||||
根据sheet_name 处理数据
|
||||
"""
|
||||
context_temp = OrderedDict()
|
||||
|
||||
if sheet_name == "封面":
|
||||
context_temp['project'] = self.project
|
||||
context_temp['sheet_name'] = sheet_name
|
||||
# 处理更新记录
|
||||
Scenario_table = []
|
||||
lines = datas[4:]
|
||||
for line in lines:
|
||||
cells = line
|
||||
# 处理换行
|
||||
for index, cell in enumerate(cells):
|
||||
#因为py2的编码问题,不能判断str
|
||||
#isinstance(cell,str)
|
||||
if not isinstance(cell,(int,float)):
|
||||
cells[index] = cell.replace('\n', '\\n')
|
||||
Scenario_table.append(cells)
|
||||
context_temp['Scenario_table'] = Scenario_table
|
||||
|
||||
elif sheet_name == "统计表":
|
||||
context_temp['project'] = self.project
|
||||
context_temp['sheet_name'] = sheet_name
|
||||
|
||||
elif sheet_name == "基础功能测试用例":
|
||||
context_temp['project'] = self.project
|
||||
context_temp['sheet_name'] = sheet_name
|
||||
# 处理基础测试用例中的数据
|
||||
Scenario_table = OrderedDict()
|
||||
lines = datas[2:]
|
||||
for line in lines:
|
||||
cells = line[0:9]
|
||||
#补全合并单元格的信息
|
||||
#模块
|
||||
if cells[0]:
|
||||
model = cells[0]
|
||||
else:
|
||||
cells[0] = model
|
||||
#子模块
|
||||
if cells[1]:
|
||||
sub_model = cells[1]
|
||||
else:
|
||||
cells[1] = sub_model
|
||||
#处理编号
|
||||
if '-ST-' in cells[2]:
|
||||
cells[2] = 'NUM'
|
||||
# 处理换行
|
||||
for index, cell in enumerate(cells):
|
||||
if not isinstance(cell,(int,float)):
|
||||
cells[index] = cell.replace('\n', '\\n')
|
||||
#以模块为单位存储
|
||||
if model not in list(Scenario_table.keys()):
|
||||
Scenario_table[model] = []
|
||||
Scenario_table[model].append(cells)
|
||||
context_temp['Scenario_table'] = Scenario_table
|
||||
|
||||
elif sheet_name == "异常测试":
|
||||
context_temp['project'] = self.project
|
||||
context_temp['sheet_name'] = sheet_name
|
||||
# 处理更新记录
|
||||
Scenario_table = []
|
||||
lines = datas[4:]
|
||||
for line in lines:
|
||||
cells = line[0:8]
|
||||
cells[0] = 'NUM'
|
||||
# 处理换行
|
||||
for index, cell in enumerate(cells):
|
||||
if not isinstance(cell,(int,float)):
|
||||
cells[index] = cell.replace('\n', '\\n')
|
||||
Scenario_table.append(cells)
|
||||
context_temp['Scenario_table'] = Scenario_table
|
||||
|
||||
elif sheet_name == "性能测试":
|
||||
context_temp['project'] = self.project
|
||||
context_temp['sheet_name'] = sheet_name
|
||||
|
||||
return context_temp
|
||||
|
||||
def feature_tpl(self):
|
||||
"""
|
||||
拿处理后的数据来渲染指定的模板
|
||||
"""
|
||||
# 读取模板
|
||||
tpl = os.path.join(self.templates_dir, self.feature_name + ".j2")
|
||||
tpl_data = io.open(tpl, encoding="utf-8").read()
|
||||
# 渲染模板
|
||||
env = Environment()
|
||||
text = env.from_string(tpl_data).render(self.context)
|
||||
# 保存文件
|
||||
xl2fe.save_feature(self, text)
|
||||
|
||||
def save_feature(self, text):
|
||||
"""
|
||||
保存渲染好的模板为feature文件
|
||||
"""
|
||||
#为了解决windows换行符的问题转为二进制,主要是由于py2中open不支持newline参数
|
||||
#py2没有bytes()函数
|
||||
#text_bytes = bytes(text,'utf-8')
|
||||
text_bytes = text.encode('utf-8')
|
||||
feature_path = os.path.join(self.project_dir, self.feature_name)
|
||||
# 写入文件
|
||||
with open(feature_path, 'wb+') as fp:
|
||||
fp.write(text_bytes)
|
||||
|
||||
def main(self):
|
||||
xlsx_files = os.listdir(self.excel_files_dir)
|
||||
for xlsx_file in xlsx_files:
|
||||
# 排除掉非xlsx结尾的文件
|
||||
if not fnmatch(xlsx_file, "*.xlsx"):
|
||||
continue
|
||||
self.project = xlsx_file.split('_')[0]
|
||||
self.xlsx_file_path = os.path.join(self.excel_files_dir, xlsx_file)
|
||||
# 按项目存放
|
||||
self.project_dir = os.path.join(self.output_dir, self.project)
|
||||
os.mkdir(self.project_dir)
|
||||
|
||||
xl2fe.read_xlsx(self)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_env = xl2fe()
|
||||
test_env.main()
|
|
@ -0,0 +1,101 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
create zip 安装包
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os.path
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
|
||||
def _copytree(src, dst, ignore=None):
|
||||
|
||||
names = os.listdir(src)
|
||||
if ignore is not None:
|
||||
ignored_names = ignore(src, names)
|
||||
else:
|
||||
ignored_names = set()
|
||||
try:
|
||||
os.makedirs(dst)
|
||||
except Exception:
|
||||
pass
|
||||
errors = []
|
||||
for name in names:
|
||||
if name in ignored_names:
|
||||
continue
|
||||
srcname = os.path.join(src, name)
|
||||
dstname = os.path.join(dst, name)
|
||||
try:
|
||||
if os.path.isdir(srcname):
|
||||
shutil.copytree(srcname, dstname, ignore=ignore)
|
||||
else:
|
||||
# Will raise a SpecialFileError for unsupported file types
|
||||
shutil.copy2(srcname, dstname)
|
||||
# catch the Error from the recursive copytree so that we can
|
||||
# continue with other files
|
||||
except shutil.Error as err:
|
||||
errors.extend(err.args[0])
|
||||
except EnvironmentError as why:
|
||||
errors.append((srcname, dstname, str(why)))
|
||||
try:
|
||||
shutil.copystat(src, dst)
|
||||
except OSError as why:
|
||||
if WindowsError is not None and isinstance(why, WindowsError):
|
||||
# Copying file access times may fail on Windows
|
||||
pass
|
||||
else:
|
||||
errors.extend((src, dst, str(why)))
|
||||
if errors:
|
||||
raise shutil.Error(errors)
|
||||
|
||||
|
||||
def _zip_file(target_dir):
|
||||
root_dir = os.path.dirname(target_dir)
|
||||
os.chdir(root_dir)
|
||||
shutil.make_archive(os.path.basename(target_dir), format="gztar",
|
||||
base_dir=os.path.basename(target_dir))
|
||||
|
||||
|
||||
def _strip_py(py_dir):
|
||||
for base, dirs, files in os.walk(py_dir):
|
||||
for name in files:
|
||||
if name.endswith('.py'):
|
||||
path = os.path.join(base, name)
|
||||
logging.debug("Deleting %s", path)
|
||||
os.unlink(path)
|
||||
|
||||
|
||||
def main():
|
||||
# src_dir = sys.argv[1]
|
||||
site_pacakge_dir = sys.argv[2]
|
||||
target_dir = sys.argv[3]
|
||||
|
||||
top_dir = sys.argv[4]
|
||||
|
||||
shutil.rmtree(target_dir, ignore_errors=True)
|
||||
os.makedirs(target_dir)
|
||||
|
||||
for dir in ("bin", "excel_files", "templates"):
|
||||
_copytree(os.path.join(top_dir, dir),
|
||||
os.path.join(target_dir, dir))
|
||||
|
||||
shutil.copy2(os.path.join(top_dir, "README.txt"),
|
||||
os.path.join(target_dir, "README.txt"))
|
||||
|
||||
target_lib_dir = os.path.join(target_dir, "lib")
|
||||
_copytree(site_pacakge_dir, target_lib_dir)
|
||||
|
||||
_zip_file(target_dir)
|
||||
|
||||
print("")
|
||||
print("output dir %s" %(target_dir))
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except Exception:
|
||||
logging.exception("main except")
|
||||
sys.exit(1)
|
|
@ -0,0 +1,4 @@
|
|||
MarkupSafe==2.0.1; python_version > "2.7"
|
||||
MarkupSafe==1.1.1; python_version <= "2.7"
|
||||
xlrd==1.2.0
|
||||
Jinja2==2.11.2
|
|
@ -0,0 +1,32 @@
|
|||
from setuptools import setup, find_packages
|
||||
|
||||
|
||||
install_requires=[]
|
||||
|
||||
for line in open('requirements.txt'):
|
||||
install_requires.append(line.strip())
|
||||
|
||||
setup(name='excel2feature',
|
||||
version='0.0.1',
|
||||
description='',
|
||||
long_description="""\
|
||||
""",
|
||||
# Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers # nopep8
|
||||
classifiers=[
|
||||
"Programming Language :: Python",
|
||||
],
|
||||
keywords='',
|
||||
author='mh',
|
||||
author_email='menghan@lzy.com',
|
||||
url='',
|
||||
license='GPL',
|
||||
packages=find_packages(exclude=["ez_setup","test.*", "test"]),
|
||||
namespace_packages=[],
|
||||
include_package_data=True,
|
||||
test_suite='nose.collector',
|
||||
zip_safe=False,
|
||||
install_requires=install_requires,
|
||||
entry_points="""
|
||||
# -*- Entry points: -*-
|
||||
""",
|
||||
)
|
|
@ -0,0 +1,32 @@
|
|||
# encoding:UTF-8
|
||||
@{{ project }}
|
||||
@excel
|
||||
Feature: {{ sheet_name }}
|
||||
|
||||
Background:
|
||||
Given I active "{{ sheet_name }}"
|
||||
|
||||
Scenario: 更新记录
|
||||
Then I set "A1" value
|
||||
"""
|
||||
{{ project | upper }}测试用例
|
||||
"""
|
||||
And I load the table
|
||||
| 版本号| 修改日期 | 修改内容 | 修订人 |
|
||||
{%- for lines in Scenario_table %}
|
||||
| {{ lines |join(' | ') }} |
|
||||
{%- endfor %}
|
||||
|
||||
|
||||
Scenario: 调整样式
|
||||
# 指定区内自动换行
|
||||
Then I auto set wrap start at "A5"
|
||||
"""
|
||||
{
|
||||
"horizontal": "left",
|
||||
"vertical": "center"
|
||||
}
|
||||
"""
|
||||
#使用的范围加上边框
|
||||
Then I auto set border
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# encoding:UTF-8
|
||||
@{{ project }}
|
||||
@excel
|
||||
Feature: {{ sheet_name }}
|
||||
|
||||
Background:
|
||||
Given I active "{{ sheet_name }}"
|
||||
|
||||
Scenario: 统计结果
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# encoding:UTF-8
|
||||
@{{ project }}
|
||||
@excel
|
||||
Feature: {{ sheet_name }}
|
||||
|
||||
Background:
|
||||
Given I active "{{ sheet_name }}"
|
||||
|
||||
{#- 以模块为单位,一个模块一个Scenario #}
|
||||
{% for model,table in Scenario_table.items() %}
|
||||
Scenario: {{ model }}
|
||||
Then I load the table
|
||||
| 功能模块 | 子模块 | 用例编号 | 用例名称 | 重要级别 | 操作步骤 | 预期结果 | 更新版本 | 备注 | 测试结果 | 测试人员 | 测试时间 |
|
||||
{#- 根据子模块,添加注释信息,起到分隔的作用 #}
|
||||
{%- set sub_model = namespace(value=None) %}
|
||||
{%- for lines in table %}
|
||||
{%- if sub_model.value != lines[1] %}
|
||||
{%- set sub_model.value = lines[1] %}
|
||||
#{{sub_model.value}}
|
||||
{%- endif %}
|
||||
| {{ lines |join(' | ') }} | | | |
|
||||
{%- endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
Scenario: 调整样式
|
||||
#自动生成用例编号
|
||||
Then I set case_number on "C"
|
||||
"""
|
||||
{{ project | upper }}-ST-
|
||||
"""
|
||||
# 指定列自动合并单元格
|
||||
Then I auto_merge_cells "A" start at "3"
|
||||
Then I auto_merge_cells "B" start at "3"
|
||||
# 指定区内自动换行
|
||||
Then I auto set wrap start at "D3"
|
||||
"""
|
||||
{
|
||||
"horizontal": "left",
|
||||
"vertical": "center"
|
||||
}
|
||||
"""
|
||||
#使用的范围加上边框
|
||||
Then I auto set border
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# encoding:UTF-8
|
||||
@{{ project }}
|
||||
@excel
|
||||
Feature: {{ sheet_name }}
|
||||
|
||||
Background:
|
||||
Given I active "{{ sheet_name }}"
|
||||
|
||||
Scenario: 添加异常测试
|
||||
Then I load the table
|
||||
| 序号 | JIRA号 | 版本号 | 问题描述 | 操作步骤 | 测试数据 | 预期结果 | 是否自动化 |
|
||||
{%- for lines in Scenario_table %}
|
||||
| {{ lines |join(' | ') }} |
|
||||
{%- endfor %}
|
||||
|
||||
|
||||
Scenario: 调整样式
|
||||
#自动生成用例编号
|
||||
Then I set case_number on "A"
|
||||
#自动换行并居中
|
||||
Then I auto set wrap start at "D5"
|
||||
"""
|
||||
{
|
||||
"horizontal": "left",
|
||||
"vertical": "center"
|
||||
}
|
||||
"""
|
||||
#使用的范围加上边框
|
||||
Then I auto set border
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# encoding:UTF-8
|
||||
@{{ project }}
|
||||
@excel
|
||||
Feature: {{ sheet_name }}
|
||||
|
||||
Background:
|
||||
Given I active "{{ sheet_name }}"
|
||||
|
||||
Scenario: 性能测试
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
[tox]
|
||||
envlist = devenv
|
||||
minversion = 1.6
|
||||
skipsdist = False
|
||||
|
||||
[testenv]
|
||||
install_command = pip install --force-reinstall -U {opts} {packages}
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
NOSE_WITH_COVERAGE=1
|
||||
NOSE_COVER_BRANCHES=1
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
|
||||
|
||||
[testenv:devenv]
|
||||
envdir = devenv
|
||||
basepython = python3
|
||||
usedevelop = True
|
||||
commands =
|
||||
{envpython} {toxinidir}/bin/e2f.py
|
||||
|
||||
[testenv:devenv2]
|
||||
envdir = devenv2
|
||||
basepython = python2.7
|
||||
usedevelop = True
|
||||
|
||||
|
||||
[testenv:py3-release]
|
||||
basepython = python3
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
|
||||
commands =
|
||||
{envpython} {toxinidir}/release.py {envdir} {envsitepackagesdir} {toxinidir}/build/excel2feature {toxinidir}
|
||||
|
||||
|
||||
[testenv:py27-release]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
|
||||
commands =
|
||||
{envpython} {toxinidir}/release.py {envdir} {envsitepackagesdir} {toxinidir}/build/excel2feature {toxinidir}
|
||||
|
Loading…
Reference in New Issue