![0e8c48a274b84e8a587f77d9b3988baa.png](https://i-blog.csdnimg.cn/blog_migrate/798bda5136494aa01ee25c782ec637b8.jpeg)
关闭文件释放资源
转帖请注明出处!谢谢。上篇由于字数限制所以只能放在这里接着讲完~
文件操作完毕,一定要记得关闭文件f.close(),可以释放资源供其他程序使用
综合实例
在测试过程中发现被测试软件有内存泄漏的情况出现,所以要开发一套自动化脚本来实现监控目标进程的性能。完成这个功能需要用到psutil库。
psutil是一个跨平台库,能够轻松实现获取系统运行的进程和系统利用率(包括CPU、内存、磁盘、网络等)信息。它主要应用于系统监控,分析和限制系统资源及进程的管理。它实现了同等命令行工具提供的功能,如ps、top、lsof、netstat、ifconfig、who、df、kill、free、nice、ionice、iostat、iotop、uptime、pidof、tty、taskset、pmap等。目前支持32位和64位的Linux、Windows、OS X、FreeBSD和Sun Solaris等操作系统。
1. Psutil基本方法:
l psutil.cpu_times():查看cpu所有信息
l psutil.cpu_count():查看cpu逻辑个数
l psutil.cpu_count(logical=False):查看cpu物理个数
l psutil.virtual_memory():系统内存的所有信息
l psutil.total:系统总计内存
l psutil.used:系统已经使用内存
l mem.free:系统空闲内存
l psutil.swap_memory():获取swap内存信息
2. 实例:
import time,datetime,os,psutil
class Monitor():
def __init__(self,PID,file):
self.PID=PID
self.file = file
self.p = psutil.Process(self.PID)
self.file.writelines('Process name : %s' % self.p.name()+'n')
self.file.writelines('Process bin path : %s' % self.p.exe()+'n')
self.file.writelines('Process path : %s' % self.p.cwd()+'n')
self.file.writelines('Process status : %s' % self.p.status()+'n')
self.file.writelines('Process creation time : %s' % datetime.datetime.fromtimestamp(self.p.create_time()).strftime("%Y-%m-%d %H:%M:%S")+'n')
self.file.writelines('==================================Process use=================================n')
def get_mem_info(self):
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) +':' + u'Memory usage : %s%%' % self.p.memory_percent())
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+ ':' + u'进程的线程数 : %s' % self.p.num_threads())
self.file.writelines(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) +':' + u'Memory usage : %s%%' % self.p.memory_percent()+'n')
self.file.writelines(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+ ':' + u'进程的线程数 : %s' % self.p.num_threads()+'n')
def get_cpu_info(self):
cpucount = psutil.cpu_count(logical=True) # 找出本机CPU的逻辑核个数
process = psutil.Process(int(self.PID)) # 传入进程PID,实现监测功能
cpupercent = process.cpu_percent(interval=2)
cpu = int(cpupercent / cpucount) # 得到进程CPU占用,同资源检测管理器的数据
self.file.writelines(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+':'+u'CPU使用率:%s%%' % cpu+'n')
self.file.writelines(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+':'+u'CPU使用率:%s%%' % cpu+'n')
if __name__ == '__main__':
PID = 517420 #int(input('Please input PID: '))
dir_path=os.getcwd()
monitor_file=dir_path+r'monitor.txt'
print(monitor_file)
with open(r"mnoitor.txt", 'w') as f:
monitor = Monitor(PID,f)
monitor.get_mem_info()
monitor.get_cpu_info()
技术解释:上面代码监控cpu和mem情况,把监控信息保存到和脚本同一目录下的monitor.txt文件中。 代码获取进程信可以分别调用p.name() #进程名 p.exe() #进程的bin路径 p.cwd() #进程的工作目录绝对路径 p.status() #进程状态 p.create_time() #进程创建时间 p.uids() #进程uid信息 p.gids() #进程的gid信息 p.cpu_times() #进程的cpu时间信息,包括user,system两个cpu信息p.cpu_affinity() #get进程cpu亲和度,如果要设置cpu亲和度,将cpu号作为参考就好 p.memory_percent() #进程内存利用率p.memory_info() #进程内存rss,vms信息 p.io_counters() #进程的IO信息,包括读写IO数字及参数 p.connectios() #返回进程列表p.num_threads() #进程开启的线程数等。
邮件操作
在完成自动化测试后会自动发送一封测试结果报告的邮件,通知相关人员进行处理。这个功能不可能和我们自己平时发邮件一样,先打开浏览器,登录邮箱,创建邮件再发送。我们需要通过代码来完成发送邮件功能,在Python利用‘smtplib’和‘email‘模块,完成邮件的成功发送。
邮件协议
电子邮件的在网络中传输和网页一样需要遵从特定的协议,常用的电子邮件协议包括 SMTP,POP3,IMAP。其中邮件的创建和发送只需要用到 SMTP协议,所以本文也只会涉及到SMTP协议。SMTP 是 Simple Mail Transfer Protocol 的简称,即简单邮件传输协议。
SMTP(简单邮件传输协议),邮件传送代理程序使用SMTP协议来发送电邮到接收者的邮件服务器。SMTP协议只能用来发送邮件,不能用来接收邮件,而大多数的邮件发送服务器都是使用SMTP协议。SMTP协议的默认TCP端口号是25。
因为邮件发送,涉及多端(本地代码端、邮件发送服务器端、邮件接收服务器端),保证写代码没问题,不代表能成功,你的邮件提交到邮件发送服务器,发送的服务器可以给你拒绝服务(比如认为发送的内容是垃圾广告,或者你频繁请求发送),成功发送到对方邮件接收服务器后,对方的服务器也可以根据你的内容拒绝收你的邮件(如认为内容是广告诈骗等信息,或者发送过于频繁),在测试项目中我们一般用公司的邮箱,成功率会很高。
关于邮件格式 (RFC 2822),每封邮件都有两个部分:邮件头和邮件体,两者使用一个空行分隔。邮件头每个字段 (Field) 包括两部分:字段名和字段值,两者使用冒号分隔。有两个字段需要注意:From和Sender字段。From字段指明的是邮件的作者,Sender字段指明的是邮件的发送者。如果From字段包含多于一个的作者,必须指定Sender字段;如果From字段只有一个作者并且作者和发送者相同,那么不应该再使用Sender字段,否则From字段和Sender字段应该同时使用。
邮件体包含邮件的内容,它的类型由邮件头的Content-Type字段指明。RFC 2822定义的邮件格式中,邮件体只是单纯的ASCII编码的字符序列。而MIME (Multipurpose Internet Mail Extensions) (RFC 1341)是扩展邮件的格式,用以支持非ASCII编码的文本、非文本附件以及包含多个部分 (multi-part) 的邮件体等。
Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。
smtplib
smtplib库用来发送邮件。其中smtplib.SMTP([host[, port[, local_hostname[, timeout]]]]):此为SMTP类构造函数,表示与SMTP服务器之间的连接,并根据这个连接向smtp服务器发送指令,执行相关操作(如:登陆、发送邮件),且每个参数都是可选的。其中最重要的参数是host:smtp服务器主机名;port:smtp服务的端口,默认是25;
如果在创建SMTP对象的时候提供了这两个参数,在初始化的时候会自动调用connect方法去连接服务器。
smtplib.SMTP还提供了如下方法:
l SMTP.set_debuglevel(level):设置是否为调试模式。默认为False,即非调试模式,表示不输出任何调试信息。如果设置为1就表示输出调试信息
l SMTP.connect([host[, port]]):连接到指定的smtp服务器。参数分别表示smpt主机和端口。注意: 也可以在host参数中指定端口号(如:http://smpt.yeah.net:25),这样就没必要给出port参数。
l SMTP.docmd(cmd[, argstring]):向smtp服务器发送指令。
l SMTP.helo([hostname]) :使用"helo"指令向服务器确认身份。
l SMTP.login(user, password):登陆到smtp服务器,这里的user是邮箱的用户名,但是这里的password并不是你邮箱的密码,当你开启SMTP的时候会提示你设置一个密码,这里的密码就是对应的密码。现在几乎所有smtp服务器,都必须在验证用户信息合法之后才允许发送邮件。
l SMTP.sendmail(from_addr,to_addrs,msg[,mail_options,rcpt_options]):发送邮件。这里要注意一下第三个参数,msg是字符串,表示邮件。我们知道邮件一般由标题,发信人,收件人,邮件内容,附件等构成,发送邮件的时候,要注意msg的格式。这个格式就是smtp协议中定义的格式。
l SMTP.quit() :断开与smtp服务器的连接,相当于发送"quit"指令。
email负责构造邮件,模块提供如下方法:
l class email.mime.base.MIMEBase(_maintype, _subtype, **_params):这是MIME的一个基类。一般不需要在使用时创建实例。其中_maintype是内容类型,如text或者image。_subtype是内容的minor type类型,如plain或者gif。 **_params是一个字典,直接传递给Message.add_header()。
l class email.mime.multipart.MIMEMultipart([_subtype[, boundary[, _subparts[, _params]]]]:MIMEBase的一个子类,多个MIME对象的集合,_subtype默认值为mixed。boundary是MIMEMultipart的边界,默认边界是可数的。当需要发送附件的时候使用的就是这个类
l class email.mime.application.MIMEApplication(_data[, _subtype[, _encoder[, **_params]]]):MIMEMultipart的一个子类。
l class email.mime.audio. MIMEAudio(_audiodata[, _subtype[, _encoder[, **_params]]]): MIME音频对象
l class email.mime.image.MIMEImage(_imagedata[, _subtype[, _encoder[, **_params]]]):MIME二进制文件对象。主要用来发送图片
1. 实例:发送纯文本邮件:
from email.mime.text import MIMEText #导入email模块 msg = MIMEText('你好,seleniumwebdriver自动化测试...', 'plain', 'utf-8')
构造MIMEText对象时,第一个参数是邮件正文,第二个参数为MIME的subtype,传入'plain',最终的MIME就是'text/plain',最后要用utf-8编码保证多语言兼容性。实现过程如下:
A. qq邮箱SMTP
QQ邮箱 POP3 和 SMTP 服务器地址设置如下:
邮箱:http://qq.com
POP3服务器(端口995): http://pop.qq.com
SMTP服务器(端口465或587): http://smtp.qq.com
B. SMTP服务器需要身份验证。
1) 开启qq邮箱的smtp服务
为了保障用户邮箱的安全,QQ邮箱设置了POP3/SMTP/IMAP的开关。系统缺省设置是“关闭”,在用户需要这些功能时请“开启”。 首先,登录邮箱,进入设置-帐户;
![9d079fd85ab94b7a3f7622a16bec490c.png](https://i-blog.csdnimg.cn/blog_migrate/d3e60ceee601ed47207e2976458b030b.jpeg)
在“帐户”设置中,开启Pop3/SMTP服务,获得授权码,保存设置,即打开了相应的服务。
2) 实例代码:
import smtplib
from email.header import Header
from email.mime.text import MIMEText
mail_info={
"from": "1234567@qq.com",
"to": "2456789@qq.com",
"hostname": "smtp.qq.com",
"username": "1234567@qq.com",
"password": "tlnajaxviwhjbcgi",
"mail_subject": "自动化测试报告",
"mail_text": "Selenium Webdriver自动化测试报告",
"mail_encoding": "utf-8"
}
技术解释:用mail_info字典构造保存发送邮件信息的基本信息,包含发送邮件人,接收邮件人。From键保存的值是发送邮件人,to键保存的值是收邮件人,hostname键保存的邮件服务器地址,username键保存的值是登陆邮件服务器的用户名,password键保存的值是用户登录邮件服务器的密码,因为登陆的是qq服务器,所以是临时的授权码。
if __name__ == '__main__':
smtp =smtplib.SMTP_SSL(mail_info["hostname"],465) # 这里使用SMTP_SSL就是默认使用465端口
smtp.set_debuglevel(1)
smtp.ehlo(mail_info["hostname"])
smtp.login(mail_info["username"], mail_info["password"])
msg = MIMEText(mail_info["mail_text"], "plain", mail_info["mail_encoding"])
msg["Subject"] = Header(mail_info["mail_subject"], mail_info["mail_encoding"])
msg["from"] = mail_info["from"]
msg["to"] = mail_info["to"]
smtp.sendmail(mail_info["from"], mail_info["to"], msg.as_string())
smtp.quit()
注意:如果收件人地址错误,但代码还是会提示"邮件发送成功",如果是地址错误在qq邮箱中会收到"来自http://qq.com的退信"。
利用class的知识把sendmail进行封装,代码如下:
import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
class SendEmail():
outbox = "1234567@qq.com "
password = "tlnajaxviwhjbcgi"
inbox = "2456789@qq.com"
smtp_server = "smtp.qq.com"
技术解释:封装Sendmail类,outbox,password,inbox,smtp_server都是类的属性
def _format_address(self, text):
name, address = parseaddr(text)
return formataddr((Header(name, "utf-8").encode(), address))
技术解释:_format_address是私有方法,不能直接通过类实例调用。parseaddr 是email.utils.parseaddr中的方法,它的作用是解析邮件地址,原因是邮件地址很多时候在原文里是这样写的:user1 <xxxxxxxx@163.com>, email.utils.parseaddr就可以把它解析为一个列表,第一项是user1, 第二项是xxxxxxxx@163.com。
def send_email_text(self):
msg = MIMEText("Selenium Webdriver自动化测试报告", "plain", "utf-8") # 第一个参数:邮件正文 第二个参数:邮件类型 纯文本 第三个参数:编码
msg["From"] = self._format_address("测试人员 <%s>" % self.outbox) # 发件人姓名与发件箱地址
msg["To"] = self._format_address("开发经理 <%s>" % self.inbox) # 收件人姓名与收件箱地址
msg["Subject"] = Header("自动化测试报告", "utf-8").encode() # 邮件标题
try:
server = smtplib.SMTP_SSL(self.smtp_server,465) # 构造smtp服务器连接
server.set_debuglevel(1) # debug输出模式 默认关闭
server.login(self.outbox, self.password) # 登录smtp服务器
server.sendmail(self.outbox, [self.inbox], msg.as_string()) # 发送邮件
server.quit()
print("邮件发送成功")
except:
print("邮件发送失败")
if __name__ == '__main__':
SendEmail.send_email_text()
2. 实例:发送HTML邮件:
自动化结果报告中用HTML会很直观,那么要发送这种HTML邮件,主要是构造MIMEText对象时,把HTML字符串传进去,把第二个参数由plain变为html就可以了:
import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
class SendEmail():
outbox = "1234567@qq.com "
password = "tlnajaxviwhjbcgi"
inbox = "2456789@qq.com"
smtp_server = "smtp.qq.com"
def _format_address(self, text):
name, address = parseaddr(text)
return formataddr((Header(name, "utf-8").encode(), address))
def send_email_html(self):
msg = MIMEText( """<table width="800" border="0" cellspacing="0" cellpadding="4">
<tr>
<td bgcolor="#CECFAD" height="20" style="font-size:14px">测试结果分析<a href="monitor.domain.com">more>></a></td>
</tr>
<tr>
<td bgcolor="#EFEBDE" height="100" style="font-size:13px">
1)HTTP状态<br>
500:105 404:3264 503:214<br>
2)用户浏览器统计<br>
IE:50% firefox:10% chrome:30% 其他浏览器:10%<br>
3)错误页面链接<br>
/index.php 42153<br>
/login.php 5112<br>
</td>
</tr>
</table>""","html","utf-8") # 第一个参数:邮件正文 第二个参数:邮件类型 纯文本 第三个参数:编码
msg["From"] = self._format_address("来自测试人员一封邮件 <%s>" % self.outbox) # 发件人姓名与发件箱地址
msg["To"] = self._format_address("管理员 <%s>" % cls.inbox) # 收件人姓名与收件箱地址
msg["Subject"] = Header("test", "utf-8").encode() # 邮件标题
try:
server = smtplib.SMTP_SSL(cls.smtp_server,465) # 构造smtp服务器连接
server.set_debuglevel(1) # debug输出模式 默认关闭
server.login(cls.outbox, cls.password) # 登录smtp服务器
server.sendmail(cls.outbox, [cls.inbox], msg.as_string()) # 发送邮件
server.quit()
print("邮件发送成功")
except:
print("邮件发送失败")
技术解释:MIMEText第一个参数的邮件正文,用了HTML语句生成一个HTML页面,由于邮件正文长度超出了行长,所以用到了三引号。HTML报告代码是这部分代码是写死的,可以写一个生成也HTML邮件正文内容的代码,这样每次执行的信息可以作为参数传入,测试报告的内容是实时的。
if __name__ == '__main__':
SendEmail.send_email_html ()
技术解释:SenEmail类实现了send_email_html()方法,上个列子实现了发送文本内容的邮件,可以把两种方法结合在一起,进一步完善Sendemail类。
3. 实例:发送正文带图片的邮件
在测试过程中我们需要提交给开发人员更加详细的信息,有利于其快速定位bug,修改程序。那么在邮件添加bug的截图是有必要的。从技术实现上带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,所以,构造一个MIMEMultipart对象代表邮件本身,然后加上一个MIMEText作为邮件正文,再加上表示附件的MIMEBase对象即可,本例中我们在邮件正文添加一张图片。
import smtplib
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.utils import parseaddr, formataddr
from email.mime.image import MIMEImage
技术解释:email是构造邮件的类,Message类是email的核心类,它是email对象模型中基类,提供了设置和查询邮件头部,访问消息体的核心方法。从概念上讲,Message对象构成了邮件头部(Headers)和消息体(payloads)。头部格式在RFC 2822中进行了定义,每个头部由该项名字和值组成,并由冒号分割。消息体可以是简单消息对象的字符串或多个MIME容器的Message对象组成的多部分邮件。MIME中定义了Content-Type类型有7种:text(文本,例如一个文档),image(图像),audio(音频),video(视频),application(应用程序,程序的原始数据),multipart(多邮件部分,每个有单独的内容类型和编码方式),message(邮件,一个完整的电子邮件或对邮件的外部应用,如一个FTP服务器和文件名)。
MIMEMultipart类用于实现多部分邮件的功能,缺省情况下它会创建Content-Type类型为mulitpart/mixed邮件。
MIMEText实现了text类型。MIMEImage类实现了image类型。email.utils.parseaddr专门用来解析地址。它们类的继承关系:
Message
+- MIMEBase
+- MIMEMultipart
+- MIMENonMultipart
+- MIMEMessage
+- MIMEText
+- MIMEImage
MIMEBase可以表示任何对象,它们这种嵌套关系就可以构造出任意复杂的邮件。你可以通过email.mime文档查看它们所在的包以及详细的用法。
class SendEmail():
outbox = "1234567@qq.com "
password = "tlnajaxviwhjbcgi"
inbox = "2456789@qq.com"
smtp_server = "smtp.qq.com"
def _format_address(self, text):
name, address = parseaddr(text)
return formataddr((Header(name, "utf-8").encode(), address))
def send_email_html_img(self):
msg = MIMEMultipart()
msg_text = MIMEText( """<table width="800" border="0" cellspacing="0" cellpadding="4">
<tr>
<td bgcolor="#CECFAD" height="20" style="font-size:14px">测试结果分析<a href="monitor.domain.com">more>></a></td>
</tr>
<tr>
<td bgcolor="#EFEBDE" height="100" style="font-size:13px">
1)HTTP状态<br>
500:105 404:3264 503:214<br>
2)用户浏览器统计<br>
IE:50% firefox:10% chrome:30% 其他浏览器:10%<br>
3)错误页面链接<br>
/index.php 42153<br>
/login.php 5112<br>
<p><img src="cid:image1"></p><br>
</td>
</tr>
</table>""","html","utf-8") # 第一个参数:邮件正文 第二个参数:邮件类型 纯文本 第三个参数:编码
msg.attach(msg_text) # 定义图片 ID,在 HTML 文本中引用
with open(r'C:SeleniumBooktimg.jpg', 'rb') as f: # 添加附件就是加上一个MIMEBase,从本地读取一个图片:
# 设置附件的MIME和文件名,这里是png类型:
mime = MIMEBase('image', 'jpg', filename='timg.jpg')
# 加上必要的头信息:
mime.add_header('Content-Disposition', 'attachment', filename='timg.jpg')
mime.add_header('Content-ID', '<image1>')
mime.add_header('X-Attachment-Id', '0')
mime.set_payload(f.read()) # 把附件的内容读进来:
encoders.encode_base64(mime) # 用Base64编码:
msg.attach(mime) # 添加到MIMEMultipart:
msg["From"] = self._format_address("来自测试人员一封邮件 <%s>" % self.outbox) # 发件人姓名与发件箱地址
msg["To"] = self._format_address("管理员 <%s>" % self.inbox) # 收件人姓名与收件箱地址
msg["Subject"] = Header("test", "utf-8").encode() # 邮件标题
try:
server = smtplib.SMTP_SSL(self.smtp_server,465) # 构造smtp服务器连接
server.set_debuglevel(1) # debug输出模式 默认关闭
server.login(self.outbox, self.password) # 登录smtp服务器
server.sendmail(self.outbox, [self.inbox], msg.as_string()) # 发送邮件
server.quit()
print("邮件发送成功")
except:
print("邮件发送失败")
技术解释:发送带图片的邮件是利用 email.mime.multipart 的 MIMEMultipart 以及 email.mime.image 的 MIMEImage。前面介绍了MIMEImage:定义邮件的图片数据,MIMEText:定义邮件的文字数据,MIMEMultipart:负责将文字图片音频组装在一起和添加附件。邮件正文是图片的格式,用OPEN打开文件读入图片,传给mime对象,然后构造协议头添加Content-ID,用X-Attachment-Id和后面HTML代码中的<img src="cid:image1">图片关联起来,如果有多个图片,给它们依次编号,然后引用不同的cid:x即可。最后添加到MIMEMultipart()对象中,它把图片和html整合在一起。
if __name__ == '__main__':
SendEmail. send_email_html_img ()
https://zhuanlan.zhihu.com/write
Excel操作
自动化测试过程中会经常用到Excel作为外部存储的数据源,数据驱动也好关键字数据驱动也好都会用到读取excel数据,同时写入excel类型的测试报告等等。python操作excel文件的第三方类库有xlrd(同族:xlwt负责写excel)和openpylx,xlsxwriter。其中xlrd可以实现跨平台读Microsoft Excel文件。它不是借助win2com类库的COM技术来访问Excel,而是直接分析Excel文件格式,从中解析数据。因此它支持python解析任何平台上的excel文件。它对unicode支持的很好,但是由于无法像微软公司那样熟悉excel文件格式的程度,所以不能处理图表,宏,图片等嵌入对象,VBA模块,公式,注释,链接等数据类型。现在它支持的Excel版本:2004, 2003, XP, 2000, 97, 95, 5.0, 4.0, 3.0, 2.1, 2.0。而2007版本Excel出现了xlsx文件类型,目的是使Excel能存入超过65535行数据。对于2007以后版本的excel文件用openpyxl库处理,支持Python3.x。还有一个库xlsxwriter 是python用来构造xlsx文件的模块,可以向excel2007+中写text,numbers,formulas 公式以及hyperlinks超链接,合并单元格,制作excel图表等功能。注意xlsxwriter只能创建新文件,不可以修改原有文件。如果创建新文件时与原有文件同名,则会覆盖原有文件
由于以上都是第三方库,要在使用前用python的pip命令安装,在命令符窗口中执行以下命令:
pip install xlrd
pip install xlwt
pip install openpyxl
xlrd和xlwt
测试使用excel文档名称为movie.xls,内容如下:
![ae698ac5478d3e1781bdd58ca30ca92c.png](https://i-blog.csdnimg.cn/blog_migrate/5b2e6dd91a439bf683d10e4b7eead27a.jpeg)
1. 打开excel文件获取所有sheet
实例:
import xlrd
if __name__ == '__main__':
workbook = xlrd.open_workbook(r'movie.xls')
print(workbook.sheet_names())
2. 根据下标获取sheet名称
实例:
import xlrd
if __name__ == '__main__':
workbook = xlrd.open_workbook(r'movie.xls')
sheet_name = workbook.sheet_names()[0]
print(sheet_name)
3. 根据sheet索引(或名称)获取有数据的行和列数
实例:
import xlrd
if __name__ == '__main__':
workbook = xlrd.open_workbook(r' movie.xls ')
print("#$$$$$$$$$$$$$$$$$$$$$$$$$$$#")
sheet_name = workbook.sheet_by_index(0) #通过索引获取数据
print(sheet_name.name) #sheet名称
print('行数:'+ str(sheet_name.nrows)) #sheet已经写入的数据行数
print('列数:'+str(sheet_name.ncols)) #sheet已经写入的数据列数
print("#$$$$$$$$$$$$$$$$$$$$$$$$$$$#")
sheet_name = workbook.sheet_by_name('Sheet1') #通过名称获取数据
print(sheet_name.name) # sheet名称
print('行数:' + str(sheet_name.nrows)) # sheet已经写入的数据行数
print('列数:' + str(sheet_name.ncols)) # sheet已经写入的数据列数
print("#$$$$$$$$$$$$$$$$$$$$$$$$$$$#")
4. 根据sheet名称获取整行和整列的值
实例:
import xlrd
if __name__ == '__main__':
workbook = xlrd.open_workbook(r' movie.xls ')
sheet_name = workbook.sheet_by_index(0) #通过索引获取sheet
print(sheet_name.name) #sheet名称
rows = sheet_name.row_values(3)
cols = sheet_name.col_values(2)
print(rows) # 输出第三行所有的数据
print(cols) # 输出第二列所有的数据
5. 获取指定单元格的内容
实例:
import xlrd
if __name__ == '__main__':
workbook = xlrd.open_workbook(r' movie.xls ')
sheet_name = workbook.sheet_by_index(0) #通过索引获取数据
print(sheet_name.name) #sheet名称
rows1 = sheet_name.cell(1,0)
rows2 = sheet_name.cell(3,4)
print(rows1) # 输出1行0列的数据
print(rows2) # 输出3行4列所有的数据
6. 获取单元格内容的数据类型
实例:
import xlrd
if __name__ == '__main__':
workbook = xlrd.open_workbook(r'movie.xls')
sheet_name = workbook.sheet_by_index(0) #通过索引获取数据
print(sheet_name.name) #sheet名称
rows_type = sheet_name.cell(1,0).ctype
print(rows_type) # 输出1行0列的数据类型
说明:ctype : 0 empty,1 string, 2 number, 3 date, 4 boolean, 5 error
openpyxl
openpyxl主要用到三个概念:Workbooks,Sheets,Cells。Workbook就是一个excel工作表;Sheet是工作表中的一张表页;Cell就是简单的一个格。openpyxl就是围绕着这三个概念进行的,不管读写都是“三板斧”:打开Workbook,定位Sheet,操作Cell。操作movie.xlsx内容同上:
![ae698ac5478d3e1781bdd58ca30ca92c.png](https://i-blog.csdnimg.cn/blog_migrate/5b2e6dd91a439bf683d10e4b7eead27a.jpeg)
1. 打开excel文件获取所有sheet
实例:
from openpyxl import load_workbook
if __name__ == '__main__':
wb = load_workbook(r"movie.xlsx")
print(wb.sheetnames) # ['Sheet1', 'Sheet2', 'Sheet3']
2. 根据下标获取sheet名称
实例:
from openpyxl import load_workbook
if __name__ == '__main__':
wb = load_workbook(r" movie.xlsx")
print(wb.sheetnames[0]) # 获取sheet1
3. 根据sheet索引(或名称)获取写入数据的行数和列数
实例:
from openpyxl import load_workbook
if __name__ == '__main__':
wb = load_workbook(r"C: movie.xlsx")
sheetnames = wb.get_sheet_names()
ws = wb.get_sheet_by_name(sheetnames[0])
print(ws.max_row) #输出存在数据的行数
print(ws.max_column) #输出存在数据的列数
4. 获取指定单元格的内容
实例:
from openpyxl import load_workbook
if __name__ == '__main__':
wb = load_workbook(r"C: movie.xlsx")
sheetnames = wb.get_sheet_names()
ws = wb.get_sheet_by_name(sheetnames[0])
wvalue = ws.cell(row=2, column=1).value
print(wvalue) #输出制定cell表格的内容
Xlsxwriter
xlsxWriter支持多种excle功能;与excel完美兼容;写大文件,速度快且只占用很小的内存空间,不支持读或者改现有的excel文件,xlsxwriter库的核心就是其Workbook,Worksheet,chart对象,下面介绍下它们的常用方法:
1. Workbook类
l Workbook类创建一个XlsxWriter的Workbook对象,代表整个电子表格文件,存储到磁盘上.
l add_worksheet():用来创建工作表,默认为sheet1
l add_format():创建一个新的格式对象来格式化单元格
l add_chart(options):创建一个图表对象,内部是使用insert_chart()方法来实现的,options(dict类型)为图表指定一个字典属性
l close():关闭文件
2. Worksheet类
l worksheet代表一个Excel的工作表,是XlsxWriter的核心,下面是几个核心方法
l write(row,col,*args):写普通数据到工作表的单元格,row行坐标,col列坐标,起始都是以0开始,*args为写入的内容,可以是字符串,文字,公式等,writer方法已经作为其它更具体数据类型方法的别名
l write_string():写入字符串类型,worksheet.write_string(0,0,'your text')
l write_number():写入数字类型,worksheet.write_number('A2',1.1)
l write_blank():写入空类型数据,worksheet.write_blank('A2',None)
l wirte_formula():写入公式类型,worksheet.write_formula(2,0,'=SUM(B1:B5))
l write_datetime():写入日期类型数据
l write_boolean():写入逻辑类数据,worksheet.write_boolean(0,0,True)
l write_url():写入超链接类型数据
l write_column():写入到一列,后面接一个数组
l wirte_row():写入到一行,后面接一个数组
l set_row(row,height,cell_format,options):此方法设置行单元格的属性,row指定行位置,height指定高度,单位是像素,cell_format指定格式对象,参数options设置hiddeen(隐藏),level(组合分级),collapsed(折叠)
l set_column(first_col,last_col,width,cell_format,options):设置列单元格的属性
l insert_image(row,col,image[,options]):此方法是插入图片到指定单元格
3. Chart类
l Chart类实现XlsxWriter模块中的图标组件的基类,支持的图表类型包括面积,条形图,柱形图,折形图,饼图,散点图,股票和雷达。一个图表对象是通过Workbook的add_chart方法创建,通过{type,'图表类型'}字典参数指定图表的类型:
l area:创建一个面积样式的图表;
l bar:创建一个条形样式的图表;
l column:创建一个柱形样式的图表;
l line:创建一个线条样式的图表
l pie:创建一个饼图样式的图表
l scatter:创建一个散点样式的图表
l stock:创建一个股票样式的图表;
l radar:创建一个雷达央视的图表
然后通过insert_chart()方法插入到指定的位置,语句:worksheet.insert_chart('A7',chart)
实例
输出测试报告,用自Xlsxwriter类输出自定义自动化测试执行分析报告样例:
import xlsxwriter
workbook = xlsxwriter.Workbook(r'report.xlsx') # 创建一个Excel文件
worksheet = workbook.add_worksheet()# 创建一个工作表sheet对象,使用默认名称:"Sheet1"
chart = workbook.add_chart({'type':'column'}) # 创建一个图表对象
技术解释:import导入xlswriter库,创建workbook实例,创建测试报告report.xlsx文件。
# 定义数据表头
title = [u'测试模块',u'迭代1',u'迭代2',u'迭代3',u'迭代4',u'迭代5',u'迭代6',u'迭代7',u'迭代8']
buname = [u'首页',u'购物',u'注册',u'查询',u'支付'] # 定义业务名称列表
data = [ # 定义5个功能迭代测试7次的数据列表
[145,152,158,199,155,145,148],
[89,858,95,6,98,344,99],
[201,200,455,175,754,198,195],
[175,657,78,78,223,765,719],
[88,815,837,90,93,88,84]
]
技术解释:我们虚拟创建一个测试报告,自行构造data数据,主要是每次迭代的测试用例执行的次数。Buname是构造了5个业务模块的名称,作为创建的行名称,title是表格的列名称。
formatter = workbook.add_format()# 定义数据formatter格式对象,设置边框加粗1像素
formatter.set_border(1) # 定义数据formatter格式对象,设置边框加粗1像素
# 定义标题栏格式对象:边框加粗1像素,背景色为灰色,单元格内容居中、加粗
title_formatter = workbook.add_format()
title_formatter.set_border(1)
title_formatter.set_bg_color('#cccccc')
title_formatter.set_align('center')
title_formatter.set_bold()
# 定义平均值栏数据格式对象:边框加粗1像素,数字按2位小数显示
ave_formatter = workbook.add_format()
ave_formatter.set_border(1)
ave_formatter.set_num_format('0.00')
技术解释:上面代码主要是创建表格的格式,set_border(1)主要作用是给框设置粗细,set_bg_color这是表格背景颜色,set_align('center')这是文字在表格中央。
def chart_series(cur_row): # 定义图表数据系列函数
chart.add_series({
'categories':'=Sheet1!$B$1:$H$1',
'values':'=Sheet1!$B${}:$H${}'.format(cur_row,cur_row),
'line':{'color':'black'},
'name':'=Sheet1!$A${}'.format(cur_row)
})
# 注:其中categories表示x轴,values表示y轴,line表示线条样式,name表示图例项
# 下面分别以行和列的方式将标题栏、测试模块、每次迭代测试次数,并引用不同的格式对象
worksheet.write_row('A1',title,title_formatter)
worksheet.write_column('A2',buname,formatter)
# 写入第2到第6行的数据,并将第2~6行数据加入图表系列
for i in range(2,7):
worksheet.write_row('B{}'.format(i),data[i-2],formatter)
# 计算每次迭代的测试模块用例执行数
worksheet.write_formula('I{}'.format(i),'=AVERAGE(B{}:H{})'.format(i,i),ave_formatter)
chart_series(str(i)) # 将每一行数据加入图表序列
chart.set_size({'width':577,'height':287}) # 设置图表大小
chart.set_title({'name':u'测试报告'}) # 设置图表大标题
chart.set_y_axis({'name':'测试用例数/迭代'}) # 设置y轴小标题
worksheet.insert_chart('A8',chart) # 在A8单元格插入图表
技术解释:上面代码完成图表的数据导入和显示,Sheet1!$B$1:$H$1'都是excel表达式,定位到指定表格获取数据。
workbook.close()# 关闭Excel文档
技术解释:关闭wrkbook工作簿。
数据库操作
在自动化测试过程中需要比对测试结果,如数据库中提取测试结果数据与前台ui界面数据进行比对,还有就是自动化测试过程中需要进行数据驱动,而文本文件,excel,xml中存储的测试数据都是有限的,数据库是首选,所以我们要学会基本的操作数据的方法。Python提供了多种操作数据库的手段,包括odbc,dao,ado,以及python专有模块等方式,python的shelve模块可以模拟小型数据库,支持以字典的方式访问数据库。SQLite是一种嵌入式的数据库,一般会作为测试开发提供给业务测试人员的自动化测试平台的后台。
python DB-API的使用流程是:引入API模块,获取与数据库的连接,执行SQL语句,关闭数据库连接四个步骤。我们这里学习操作Mysql数据库(下面案例需要自行安装mysql),python中操作mysql的MySQLdb驱动从2014年1月停止了维护,Python3版本已经用PyMySQL,pymysql和mysqldb的操作基本上是类似的,
pymysql常用操作如下:
1. connection对象支持的方法
l cursor() 使用该连接创建并返回游标
l commit() 提交当前事务
l rollback() 回滚当前事务
l close() 关闭连接
2. cursor对象支持的方法
l execute(op) 执行一个数据库的查询命令
l fetchone() 取得结果集的下一行
l fetchmany(size) 获取结果集的下几行
l fetchall() 获取结果集中的所有行
l rowcount() 返回数据条数或影响行数
l close() 关闭游标对象
实例:
1. 在学习操作前在mysql数据库中创建数据库和表:
CREATE DATABASE bank;
DROP TABLE IF EXISTS `acount`;
CREATE TABLE `acount` (
`id` int(4) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(6) NOT NULL COMMENT '用户姓名',
`account` varchar(12) NOT NULL COMMENT '银行账号',
`saving` decimal(8,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '储蓄金额',
`expend` decimal(8,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '支出总计',
`income` decimal(8,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '收入总计',
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `trade` VALUES (1,'徐小平','18811051469',0.00,0.00,0.00);
技术解释:如果数据库中存在acount表,就把它从数据库中drop掉。备份sql中一般都有这样的语句,如果是数据库中有这个表,先drop掉,然后create表,然后再进行数据插入。
2. Python代码:
import pymysql.cursors
# 连接数据库
connect = pymysql.Connect(
host='localhost',
port=3310,
user='woider',
passwd='3243',
db='bank',
charset='utf8'
)
cursor = connect.cursor()# 获取游标
# 插入数据
sql = "INSERT INTO trade (name, account, saving) VALUES ( '%s', '%s', %.2f )"
data = ('雷军', '13512345678', 10000)
cursor.execute(sql % data)
connect.commit()
print('成功插入', cursor.rowcount, '条数据')
# 修改数据
sql = "UPDATE trade SET saving = %.2f WHERE account = '%s' "
data = (8888, '13512345678')
cursor.execute(sql % data)
connect.commit()
print('成功修改', cursor.rowcount, '条数据')
# 查询数据
sql = "SELECT name,saving FROM trade WHERE account = '%s' "
data = ('13512345678',)
cursor.execute(sql % data)
for row in cursor.fetchall():
print("Name:%stSaving:%.2f" % row)
print('共查找出', cursor.rowcount, '条数据')
# 删除数据
sql = "DELETE FROM trade WHERE account = '%s' LIMIT %d"
data = ('13512345678', 1)
cursor.execute(sql % data)
connect.commit()
print('成功删除', cursor.rowcount, '条数据')
# 事务处理
sql_1 = "UPDATE trade SET saving = saving + 1000 WHERE account = '18012345678' "
sql_2 = "UPDATE trade SET expend = expend + 1000 WHERE account = '18012345678' "
sql_3 = "UPDATE trade SET income = income + 2000 WHERE account = '18012345678' "
技术解释:pymysql.Connect也可以用字典的方式作为参数,如:
config = {
'host':' localhost ',
'port':3310,
'user':'root',
'password':'3243',
'db':'bank',
'charset':' utf8',
}
connection = pymysql.connect(**config)
cursor.execute执行SQL语句。
try:
cursor.execute(sql_1) # 储蓄增加1000
cursor.execute(sql_2) # 支出增加1000
cursor.execute(sql_3) # 收入增加2000
except Exception as e:
connect.rollback() # 事务回滚
print('事务处理失败', e)
else:
connect.commit() # 事务提交
print('事务处理成功', cursor.rowcount)
# 关闭连接
cursor.close()
connect.close()
技术解释:代码中用到cursor,也就是游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标充当指针的作用。尽管游标能遍历结果中的所有行,但他一次只指向一行。概括来讲,SQL的游标是一种临时的数据库对象,即可以用来存放在数据库表中的数据行副本,也可以指向存储在数据库中的数据行的指针。游标提供了在逐行的基础上操作表中数据的方法。游标的一个常见用途就是保存查询结果,以便以后使用。游标的结果集是由SELECT语句产生,如果处理过程需要重复使用一个记录集,那么创建一次游标而重复使用若干次,比重复查询数据库要快的多。