python+behave+openpyxl管理测试用例

测试用例文本化,使用python+behave来维护测试用例

1.背景

测试用例一般都是用excel去维护的,这也是行业内大部分公司的做法。

近期由于公司leader的要求:“你们测试用例要文本化,主要是方便diff,不然每次提交的都是xls文件(测试用例会提交到git仓库),不太方便去比较。如果文本化了,就能在git中直接看出这次提交修改的内容”。

基于这个需求,其实有很多更好用的excel对比工具,但是大佬是研发类型的大佬,更希望能够文本化处理。即通过某种方式,将写好的测试用例转成文本,然后再通过CI/CD的方式编译出我们需要的excel。相当于提交到git仓库的不再是excel,而是转换后的文本。

2.项目介绍

behave的介绍:BDD-python+behave自动化测试搭建

分两个部分,一个是将excel转换为behave所需要的feature,一个是将feature转换为excel,从而达到相互转换的。

2.1 将原有的excel转化为feature

通常情况下,excel的模板都是固定的。同公司中,不同项目所使用的测试用应该是基于同一个模板编写的。

这里就是针对基于固定模板编写完成的测试用例文件进行分析,并转换为feature文件

项目地址:https://gitea.kiki.kim/ha/excel2feature.git

目录结构

1
2
3
4
5
6
7
8
+--excel2feature/
| +--bin/
| | +-- e2f.py # -- 主程序
| +--excel_files/ # -- 测试用例文件夹
| | +-- *.xlsx # 测试用例
| +--templates/ # -- features模板
| | +-- *feature.j2 # 模板文件
| +--output/ # -- 转换后的feature

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        #获取所有的数据
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)]
.........
.........

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
.........
.........
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)


2.2 将feature转换为excel

由于提交的都是feature文件,这种方式是无法直接去使用的。因此,需要再将其转为excel文件。

项目地址:https://gitea.kiki.kim/ha/behave-test-case.git

项目结构:

1
2
3
4
5
6
7
8
+--behave-test-case/
| +--bin/
| | +-- behave_main.py # -- 主程序
| +--features/
| | +-- *.feature # 转换后的测试用例
| +--fixtures/ # 模板文件目录
| | +-- test_case_template.xlsx # 模板文件
| +--output/ # -- 转换后的目录

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#激活sheet页
@step(u'I active "{title}"')
def i_active_title(context,title):
# context.project_file = os.path.join(context.output_dir,context.file)
# context.wb = load_workbook(context.project_file)
#print(title)
context.ws = context.wb.get_sheet_by_name(title)
.........
.........
#自动合并单元格
@step(u'I auto_merge_cells "{col}" start at "{startnum}"')
def i_auto_merge_cells(context,col,startnum):
status = True
startnum = int(startnum)
endnum = startnum + 1
#print(endnum)
while status:
startcol = col + str(startnum)
endcol = col +str(endnum)
if context.ws[endcol].value == None or context.ws[endcol].value == '':
status = False
#continue
if context.ws[startcol].value == context.ws[endcol].value:
endnum = endnum +1
else:
endnumtmp = endnum -1
endcoltmp = col +str(endnumtmp)
cells = startcol + ":" + endcoltmp
context.ws.merge_cells(cells)
context.ws[startcol].alignment = my_alignment('center', 'center')
startnum = endnum
endnum = endnum +1
.........
.........
#写入数据
@step(u'I load the table')
def i_load_table(context):
table = context.table
#print(table)
if context.text:
title = table.headings
context.ws.append(title)
lists = table.rows
for cells_list in lists:
cells = cells_list.cells
values = []
for cell in cells:
#换行符被转义了,再处理回来
cell_value = cell.replace('\\n','\n')
values.append(cell_value)
#print(values)
context.ws.append(values)