需求
1.读取一个已有的word文档。docx格式。
2.在该word文档中,通过一个给定的文字。找到该位置。在该位置的下方添加一个表格。例如在图中“BUG情况表”的下方插入一个表格
3.表格内容如下。要求添加完该表格后,如果表格内容发生变更。还能再次通过该程序,修改表格里的数据。
设计
通过python-docx读取word文档。通过document.paragraphs定位指定文字的位置。
通过xlwings读取excel的内容,存成list[list[]]。
通过docx的add_table增加一个表格,并且更改表头颜色,合并表格等操作
通过识别表头的第一行,判断是否是已经存在这个表格,来决定是否要删除原表格
代码
# -*- coding: UTF-8 -*-
import sys
from copy import deepcopy
import xlwings
from docx import Document
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
def copy_table_after(table, paragraph):
tbl, p = table._tbl, paragraph._p
new_tbl = deepcopy(tbl)
p.addnext(new_tbl)
def move_table_after(table, paragraph):
tbl, p = table._tbl, paragraph._p
p.addnext(tbl)
def get_excel_date(filename):
'''
获得excel里的所有内容,返回list
:param filename: excel路径
:return: list[list[]]
'''
app = xlwings.App(visible=False, add_book=True)
app.display_alerts = False
app.screen_updating = False
wb = app.books.open(filename)
sht = wb.sheets[0]
rng = sht.range('A1')
# 把excel里的数据读取成 年-月-日 时:分:秒的格式
my_date_handler = lambda year, month, day, hour, minute, second, **kwargs: "%04i-%02i-%02i %02i:%02i:%02i" % (
year, month, day, hour, minute, second)
# 取出所有内容,这里用ig这个变量,是为了庆祝I.G获得LOL S8赛季总冠军
ig = rng.current_region.options(index=False, numbers=int, empty='N/A', dates=my_date_handler)
result = ig.value
wb.close()
app.quit()
return result
def delete_table_with_title(document,expect_text):
allTables = document.tables
for activeTable in allTables:
if activeTable.cell(0, 0).paragraphs[0].text == expect_text:
print('删除成功')
activeTable._element.getparent().remove(activeTable._element)
def insert_table_after_text(file_name,excel_name,expect_text):
document = Document(file_name)
# 因为docx读出来的都是unicode类型的,所以我们要用unicode类型的进行查找
expect_text=expect_text.decode('utf-8')
delete_table_with_title(document,expect_text)
target = None
for paragraph in document.paragraphs:
paragraph_text = paragraph.text
if paragraph_text.endswith(expect_text):
target = paragraph
break
if target is not None:
records = get_excel_date(excel_name)
# 获得excel数据的栏数,初始化一个空的table
col = len(records[0])
table = document.add_table(rows=1, cols=col)
table.style = 'Table Grid'
# 给table加一个表头,并且合并第一栏
shading_elm_1 = parse_xml(r'<w:shd {} w:fill="D9E2F3"/>'.format(nsdecls('w')))
table.rows[0].cells[0]._tc.get_or_add_tcPr().append(shading_elm_1)
table.rows[0].cells[0].text=expect_text
table_row=table.rows[0]
first=table_row.cells[0]
end=table_row.cells[-1]
first.merge(end)
# 合并结束,开始把excel里的内容添加到table里
for tr_list in records:
row_cells = table.add_row().cells
index = 0
for td_list in tr_list:
row_cells[index].text = td_list
index = index + 1
# 把添加的table移动到指定的位置
move_table_after(table, target)
# 保存
document.save(file_name)
if __name__ == '__main__':
insert_table_after_text('demo2.docx', 'demo.xlsx',"BUG情况表")
最终效果
需求
假定有如主图相同的http请求。我们一般的做法是,用postman去抓取http请求,然后修改request的body或者header里的数据,点击send按钮,检查返回的response的body是否正确。
对于输入。一般来说,我们会纯手工,或者半自动的,设计测试用例。例如使用边界值分析,等价类划分等方法,用在我们的输入参数中。比如我参数中的configname最多200个参数,我测试输入201个参数。
对于输出。一般来说,我们大部分时候是肉眼检查,或者写代码,通过jsonpath取参数,然后判断是否存在来检查。
这里我打算用一个新的方法来降低测试的手工特性,让他更自动化一点。以下想法还处于调试阶段,用于大规模使用,暂时不行。
设计
输入修改方案:引入faker库和jsonschema库。通过这两个库,我们可以产生随机的json串
faker是我无意之间发现的,能按照规律产生随机字的库,例如
fake.name()
是产生一个随机的名字,只要加入适当的providers,就能按照需要的规则产生随机字
jsonschema这个用的人很多,这里就不介绍了,下面推荐一个网站,能把json请求转换为schema格式
https://jsonschema.net/
schema中会注明每个字段的规则,例如是string类型还是integer。
输出修改方案:使用jsonschma的validate方法来检查(这种检查方法目前有一些检查不充分,但是已经可以让测试人员减少一些工作量了)
jsonschema.validate(response, schema)
使用方案
1.去postman抓取http请求,并且记录下所需要的输入json和输出json
2.打开https://jsonschema.net/ 把输入json和输入json 转换成jsonschema
3.把输入jsonschema文件,输出文件jsonschema放入相应的目录,自己写一个用于生成随机requestbody的provider和一个测试用的主函数
4.运行测试主入口文件,打印一下发送的json文件,看是不是随机化了,结果是确实随机化了。
代码
测试主入口test_json_from_schema.py
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import json
import faker
import jsonschema
import requests
from jsonschema.exceptions import ValidationError
import jsonprovider
def generate_request(request_json_schema):
'''
通过schema生成随机测试数据
:param request_json_schema:
:return:
'''
fake = faker.Faker()
fake.add_provider(jsonprovider.JSONProvider)
request_body = fake.json(json.load(open(request_json_schema)))
print(request_body)
return request_body
def check_json_schema(response, schema):
'''
通过json_schema检查返回的json串
:param response:
:param schema:
:return:
'''
result = True
try:
jsonschema.validate(response, schema)
except ValidationError, e:
print("fail")
result = False
return result
if __name__ == '__main__':
# 生成request body
body = generate_request("schema_file/create_config_request_schemas.json")
# 使用request库发送post请求
url = "https://dev.honcloud.honeywell.com.cn:8080/dashboard/clustercentre/configmng/newconfig/addconfig"
headers = {"Content-Type": "application/json", "authorization": "48a5eb61-914e-4b3a-a7a3-0b25f72d06d7"}
response = requests.post(url, data=body, headers=headers)
print(response.json())
response_json=response.json()
response_schema="schema_file/create_config_response_schemas.json"
# 用生成的response的schema来检查
result=check_json_schema(response_json,response_schema)
print(result)
jsonprovider.py可以自行百度一个faker的provider的方案,我这里做的也不好,随机出来的值只遵循了字符类型,后面会考虑融合我们的边界值分析,等价类划分的方案进来,完善这个jsonprovider.py之后再放出来
需求
读取excel里的表格里的内容,然后打开本机的outlook。把excel里的内容添加到正文里,注意。这里是要添加到正文!正文!正文!而不是添加到附件里
设计思路
1.excel处理
打开excel的方法有很多,但是在不知道excel里,行和列的大小的情况下,就能获得excel里的非空值行列的办法不多。我这边采用的是xlwings这个库,用的方法是range.current_region这个方法。这个方法会选择当前range下,有值的区域(非空区域)
通过配置options选项,可以指定excel获得的值的格式,int或者string,或者空值返回N/A
2.打开outlook
打开outlook在windows上只能用win32模块了,通过下面方法可以打开outlook并且创建一个空的email
olook = win32com.client.Dispatch("Outlook.Application")
mail = olook.CreateItem(0)
然后配置邮件的htmlbody和outlook邮件悬停(可以手动更改邮件内容,手动发送),可以用以下方法
mail.HTMLBody = body_html
mail.Display(True)
完整代码
下面是完整代码,读者修改一下excel的路径,就可以自己去试试啦
# -*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import win32com.client
import xlwings
def get_excel_date(filename):
'''
获得excel里的所有内容,返回list
:param filename: excel路径
:return: list[list[]]
'''
app = xlwings.App(visible=False, add_book=True)
app.display_alerts = False
app.screen_updating = False
wb = app.books.open(filename)
sht = wb.sheets[0]
rng = sht.range('A1')
# 把excel里的数据读取成 年-月-日 时:分:秒的格式
my_date_handler = lambda year, month, day, hour, minute, second, **kwargs: "%04i-%02i-%02i %02i:%02i:%02i" % (
year, month, day, hour, minute, second)
# 取出所有内容,这里用ig这个变量,是为了庆祝I.G获得LOL S8赛季总冠军
ig = rng.current_region.options(index=False, numbers=int, empty='N/A', dates=my_date_handler)
result = ig.value
wb.close()
app.quit()
return result
if __name__ == '__main__':
olook = win32com.client.Dispatch("Outlook.Application")
mail = olook.CreateItem(0)
mail.Recipients.Add("357244849@qq.com")
mail.Subject = "test report"
body_html = ""
body_html = body_html + '<body>Hi all:<br/>以下是XXXXX项目今天的测试情况:<br/><br/>明天的测试计划:<br/><br/>目前的bug:'
body_html = body_html + '<table width="1" border="1" cellspacing="1" cellpadding="1" height="100">'
# 这里用rng 是因为这一次rng止步8强!
rng_list = get_excel_date("C:\lzw_programming\resource\reports\CurrentVersionAllDefectTable.xlsx")
# 表头
for tr_list in rng_list[:1]:
body_html = body_html + "<tr>"
for td_list in tr_list:
# 这里也是奇葩需求,因为要求表头不能换行,所以用了nowrap
body_html = body_html + '<th bgcolor="#C3C3C3" nowrap="nowrap">' + td_list + '</th>'
body_html = body_html + "</tr>"
# 表内容
for tr_list in rng_list[1:]:
body_html = body_html + "<tr>"
for td_list in tr_list:
body_html = body_html + "<td>" + td_list + "</td>"
body_html = body_html + "</tr>"
body_html = body_html + '</table>'
body_html = body_html + "</body>"
mail.HTMLBody = body_html
mail.Display(True)
需求
python-docx是一个python的读写word的库,可以用来读写word文档,向word文档里插入表格。例如如下的操作docx的代码:
from docx import Document
document = Document()
document.add_heading('Document Title', 0)
p = document.add_paragraph('A plain paragraph having some ')
p.add_run('bold').bold = True
p.add_run(' and some ')
p.add_run('italic.').italic = True
document.add_heading('Heading, level 1', level=1)
document.add_paragraph('Intense quote', style='Intense Quote')
document.add_paragraph(
'first item in unordered list', style='List Bullet'
)
document.add_paragraph(
'first item in ordered list', style='List Number'
)
records = (
(3, '101', 'Spam'),
(7, '422', 'Eggs'),
(4, '631', 'Spam, spam, eggs, and spam')
)
table = document.add_table(rows=1, cols=3,style='Light Grid Accent 1')
hdr_cells = table.rows[0].cells
hdr_cells[0].text = 'Qty'
hdr_cells[1].text = 'Id'
hdr_cells[2].text = 'Desc'
for qty, id, desc in records:
row_cells = table.add_row().cells
row_cells[0].text = str(qty)
row_cells[1].text = id
row_cells[2].text = desc
document.add_page_break()
document.save('demo.docx')
pyinstaller是python打包成exe的工具。
当我们要把编写好的使用了python-docx的程序打包时,问题来了。
首先,命令行打包
pyinstaller -D word_generate.py
这个没问题,word_generate.py是我的主程序文件。这里打包也不报错。但是下一步,运行的时候,duang~报错了,报错如下:
C:lzw_programmingjira_testdistword_generate>word_generate.exe
Traceback (most recent call last):
File "word_generate.py", line 4, in <module>
File "site-packagesdocxapi.py", line 25, in Document
File "site-packagesdocxopcpackage.py", line 116, in open
File "site-packagesdocxopcpkgreader.py", line 32, in from_file
File "site-packagesdocxopcphys_pkg.py", line 31, in __new__
docx.opc.exceptions.PackageNotFoundError: Package not found at 'C:LZW_PR~1JIRA_T~1distWORD_G~1docxtemplatesdefault.docx'
[4232] Failed to execute script word_generate
解决方法
在翻了很多地方之后,终于找到了解决方法。很简单。增加一个hook-docx.py文件在PyInstallerhooks目录下就可以了。下面是文件内容以及路径
#-----------------------------------------------------------------------------
# Copyright (c) 2018-2018, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
from PyInstaller.utils.hooks import collect_data_files
datas = collect_data_files("docx")
路径:
需求
最近遇到一个奇葩的事,行政那边说,让估算一下明年的这些杂七杂八费,然后给了我一个excel,里面有200多个这样的费用。我没做过行政,也搞不清这个到底咋来,为什么要弄这玩意。一番交流,原来是上头要的,不一定看,但是东西得有,让我弄个数字和去年差不多的就行。于是变有了下面的故事
设计
1.需要读取excel. 用的库是xlwing。可以根据sheet名称定位sheet,然后用range()方法定位一行,一列,或者指定几个单元格。
例如:定位 A1到A3 ,range1=sheet.range("A1:A3")
具体用法很多,在xlwing的官网上有介绍。http://docs.xlwings.org/en/stable/api.html
2.需要产生随机数,用的库是numpy,产生一个加权的随机数,然后我用的加权随机数规则为:
【-10%,概率10%】【不变,概率30%】【+2%,概率30%】【+5%,概率20%】【+10%,概率10%】
代码实现
代码中分为两个function,一个是读取excel,一个是根据一个值,产生一个加权随机数。观众老爷可以参考,对有疑问的地方,可以再来与我沟通O(∩_∩)O
# -*- coding: UTF-8 -*-
import xlwings
import numpy as np
def import_excel(filename, sheet_name, source,target):
'''
导入一个excel,根据某一列的值,产生一个加权随机数,覆盖掉另一列的值
:param filename: excel路径
:param sheet_name: sheet的名字
:param source: 源列的第一个值 如:A1,C1
:param target: 目标列的第一个值,如B1,D2
:return:
'''
app = xlwings.App(visible=False, add_book=True)
app.display_alerts = False
app.screen_updating = False
wb = app.books.open(filename)
sht = wb.sheets[sheet_name]
rng1 = sht.range(source)
rng2 = sht.range(source).end('down')
rng3 = sht.range(rng1, rng2)
all_rng = rng3.value
list_dest = []
for item in all_rng:
dest_item = arithmetic(item)
# 这里要把结果变成[[1],[2]]这样的形式,才是一列的数据
# 如果是[1,2]这样,是一行的数据
list_temp = []
list_temp.append(dest_item)
list_dest.append(list_temp)
sht.range(target).value = list_dest
wb.save(filename)
wb.close()
app.quit()
def arithmetic(source):
'''
加权随机算法
:param source: 输入一个原值
:return: 返回浮动后的值
'''
power = np.array([0.1, 0.3, 0.3, 0.2, 0.1])
index = np.random.choice([-0.1, 0, 2, 5, 10], p=power.ravel())
rand = source * index / 100
dest = int(source + rand)
return dest
if __name__ == '__main__':
import_excel("Book1.xlsx", 'Sheet1','C2','D2')