源码数据库配置揭秘
在本次接口框架实战项目中的示例文件为configDB.py,放在commomsrc文件夹内。接下来我们来分析一下文件内容。文件头部是导入一些类,pymysql模块、readConfig类、log类。
import pymysql
import readConfig as readConfig
from commonsrc.Log import MyLog as Log
localReadConfig = readConfig.ReadConfig()
正文部分定义了一个大类MyDB,看到全局变量标识符global,就会知道后面的都是全局变量,然后通过readconfig类读取ini的文件内容,配置数据库连接基本验证信息。
class MyDB:
global host, username, password, port, database, config
host = localReadConfig.get_db("host")
username = localReadConfig.get_db("username")
password = localReadConfig.get_db("password")
port = localReadConfig.get_db("port")
database = localReadConfig.get_db("database")
config = {
'host': str(host),
'user': username,
'passwd': password,
'port': int(port),
'db': database
}
接下来的初始化方法__init__里初始了log类,数据库,数据库游标。真正的正文内容依次为连接数据库,执行sql语句,获取数据库所有查询内容,获取一条内容,关闭数据库。
def __init__(self):
self.log = Log.get_log()
self.logger = self.log.get_logger()
self.db = None
self.cursor = None
def connectDB(self):
"""
connect to database
:return:
"""
try:
# connect to DB
self.db = pymysql.connect(**config)
# create cursor
self.cursor = self.db.cursor()
print("Connect DB successfully!")
except ConnectionError as ex:
self.logger.error(str(ex))
def executeSQL(self, sql, params):
"""
execute sql
:param sql:
:return:
"""
self.connectDB()
# executing sql
self.cursor.execute(sql, params)
# executing by committing to DB
self.db.commit()
return self.cursor
def get_all(self, cursor):
"""
get all result after execute sql
:param cursor:
:return:
"""
value = cursor.fetchall()
return value
def get_one(self, cursor):
"""
get one result after execute sql
:param cursor:
:return:
"""
value = cursor.fetchone()
return value
def closeDB(self):
"""
close database
:return:
"""
self.db.close()
print("Database closed!")
连接数据库这一步,py文件定义的方法名为connectDB,语句self.db = pymysql.connect(**config)这里我们参数输入的是动态参数,指向之前配置的config里,然后产生游标,游标的主要作用时确认你当前操作位置是在哪里,数据库的哪里。
def connectDB(self):
"""
connect to database
:return:
"""
try:
# connect to DB
self.db = pymysql.connect(**config)
# create cursor
self.cursor = self.db.cursor()
print("Connect DB successfully!")
except ConnectionError as ex:
self.logger.error(str(ex))
执行数据库sql语句的方法里主要是先调用上面的连接数据库方法,随后执行数据库sql语句运用到了execute方法,这里大家需要注意一定要有提交方法commit。只有提交了才会执行sql语句。
def executeSQL(self, sql, params):
"""
execute sql
:param sql:
:return:
"""
self.connectDB()
# executing sql
self.cursor.execute(sql, params)
# executing by committing to DB 注意此处的事务提交
self.db.commit()
return self.cursor
如何获取查询出来的所有数据呢,这里直接是用到了cursor.fetchall()方法获取所有数据,cursor.fetchone()方法获取一条数据。
def get_all(self, cursor):
"""
get all result after execute sql
:param cursor:
:return:
"""
value = cursor.fetchall()
return value
def get_one(self, cursor):
"""
get one result after execute sql
:param cursor:
:return:
"""
value = cursor.fetchone()
return value
关闭数据库这一块,我们主要是为了安全考虑,就像打开文件的open方法一样,吸管吸的打开了就关闭掉而已。
def closeDB(self):
"""
close database
:return:
"""
self.db.close()
print("Database closed!")
邮件配置源码
在本次接口框架实战项目中的示例文件为configEmail.py,放在commomsrc文件夹内。接下来我们来分析一下文件内容。文件的头部导入的是os、smtplib、email库,zipfile方法等。
import os
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from datetime import datetime
import threading
import readConfig as readConfig
from commonsrc.Log import MyLog
import zipfile
import glob
localReadConfig = readConfig.ReadConfig()
正文部分是有两个大类一个是Email,一个是MyEmail。在Email类里,我们有这么几步操作,处理了邮件的配置信息、邮件基本头配置、邮件文本基本配置、邮件图片基本配置,邮件文件基本配置、核对需要发送的东西、邮件发送。
在初始化__init__文件里,我们对基本的身份验证配置信息做了配置,log的打印、发送时间等都有定义,定义的时候大部分采用了ini文件配置的信息。
def __init__(self):
global host, user, password, port, sender, title
host = localReadConfig.get_email("mail_host")
user = localReadConfig.get_email("mail_user")
password = localReadConfig.get_email("mail_pass")
port = localReadConfig.get_email("mail_port")
sender = localReadConfig.get_email("sender")
title = localReadConfig.get_email("subject")
# content = localReadConfig.get_email("content")
# get receiver list
self.value = localReadConfig.get_email("receiver")
self.receiver = []
for n in str(self.value).split("/"):
self.receiver.append(n)
# defined email subject
date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.subject = "接口测试报告" + " " + date
self.log = MyLog.get_log()
self.logger = self.log.get_logger()
self.msg = MIMEMultipart('related')
邮件基本头配置,这里写的比较简单就是基本的发送人和接受人。其中self.msg表示的是邮件类型是可以发送超文本和内嵌资源的类型。
def config_header(self):
"""
defined email header include subject, sender and receiver
:return:
"""
self.msg['subject'] = self.subject
self.msg['from'] = sender
self.msg['to'] = ";".join(self.receiver)
邮件文本基本配置,先打开在testFile文件夹里的,email的html样式文本。然后通过MIMEText()方法对文本进行转换为html格式,方法的最后一行是邮件图片基本配置。这里给大家留一个疑惑,这个email的html样式是不是可以自己自定义,自己找其他的样式也可以。里面有什么是要写代码关联的吗?
def config_content(self):
"""
write the content of email
:return:
"""
f = open(os.path.join(readConfig.proDir, 'testFile', 'emailStyle.txt'))
content = f.read()
f.close()
content_plain = MIMEText(content, 'html', 'UTF-8')
self.msg.attach(content_plain)
self.config_image()
邮件图片基本配置,同样是在testFile里找到对应的图片,通过MIMEImage()方法读取图片,下面我们仔细看发现这里有定义id的这么一个操作,这个是啥情况呢?在这里定义了两张图片image1和image2。这是因为在html的样式里有用到这个图片,而他们关联的唯一标识就是和。
def config_image(self):
"""
config image that be used by content
:return:
"""
# defined image path
image1_path = os.path.join(readConfig.proDir, 'testFile', 'img', 'logo.png')
fp1 = open(image1_path, 'rb')
msgImage1 = MIMEImage(fp1.read())
# self.msg.attach(msgImage1)
fp1.close()
# defined image id
msgImage1.add_header('Content-ID', '<image1>')
self.msg.attach(msgImage1)
image2_path = os.path.join(readConfig.proDir, 'testFile', 'img', 'image2.png')
fp2 = open(image2_path, 'rb')
msgImage2 = MIMEImage(fp2.read())
# self.msg.attach(msgImage2)
fp2.close()
# defined image id
msgImage2.add_header('Content-ID', '<image2>')
self.msg.attach(msgImage2)
核对需要发送的东西,这里我们代码写的是核对是否在目录下存在html的报告,实际可以核对更多的东西,代码逻辑是一样的。这里需要注意的是os.path.isfile()方法,如果检测目录含中文字符,始终返回的结果是false,在括号里可以加个os.path.join(path,files[1]).
def check_file(self):
"""
check test report
:return:
"""
reportpath = self.log.get_report_path()
#reportpath = unicode(reportpath, "utf8")
if os.path.isfile(os.path.join(reportpath)) and not os.stat(reportpath) == 0:
return True
else:
return True
邮件发送,这里一个一个的运行上面几个方法,email是python自带构造文件内容的一个模块,而这里smtp则是发送邮件的一个python自带模块。
def send_email(self):
"""
send email
:return:
"""
self.config_header()
self.config_content()
self.config_file()
try:
smtp = smtplib.SMTP()
smtp.connect(host)
smtp.login(user, password)
smtp.sendmail(sender, self.receiver, self.msg.as_string())
smtp.quit()
self.logger.info("The test report has send to developer by email.")
except Exception as ex:
self.logger.error(str(ex))
这个类是一个静态方法,通过异步发送邮件,防止线程阻塞。先加载线程锁,复制给第一个大类后在释放线程锁。达到了异步发送邮件的一个效果。
class MyEmail:
email = None
mutex = threading.RLock()
def __init__(self):
pass
@staticmethod
def get_email():
if MyEmail.email is None:
MyEmail.mutex.acquire()
MyEmail.email = Email()
MyEmail.mutex.release()
return MyEmail.email
文章原创首发于微信公众号 软件测试微课堂,更多内容欢迎关注微信公众号查看