接口框架辅助类的深度解析(上篇)

源码数据库配置揭秘

在本次接口框架实战项目中的示例文件为configDB.py,放在commomsrc文件夹内。接下来我们来分析一下文件内容。文件头部是导入一些类,pymysql模块、readConfig类、log类。

javascript 复制代码
import pymysql
import readConfig as readConfig
from commonsrc.Log import MyLog as Log

localReadConfig = readConfig.ReadConfig()

正文部分定义了一个大类MyDB,看到全局变量标识符global,就会知道后面的都是全局变量,然后通过readconfig类读取ini的文件内容,配置数据库连接基本验证信息。

css 复制代码
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语句,获取数据库所有查询内容,获取一条内容,关闭数据库。

python 复制代码
   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里,然后产生游标,游标的主要作用时确认你当前操作位置是在哪里,数据库的哪里。

python 复制代码
    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语句。

python 复制代码
    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()方法获取一条数据。

python 复制代码
    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方法一样,吸管吸的打开了就关闭掉而已。

python 复制代码
    def closeDB(self):
        """
        close database
        :return:
        """
        self.db.close()
        print("Database closed!")

邮件配置源码

在本次接口框架实战项目中的示例文件为configEmail.py,放在commomsrc文件夹内。接下来我们来分析一下文件内容。文件的头部导入的是os、smtplib、email库,zipfile方法等。

javascript 复制代码
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文件配置的信息。

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表示的是邮件类型是可以发送超文本和内嵌资源的类型。

python 复制代码
    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样式是不是可以自己自定义,自己找其他的样式也可以。里面有什么是要写代码关联的吗?

python 复制代码
    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的样式里有用到这个图片,而他们关联的唯一标识就是和。

python 复制代码
    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]).

python 复制代码
    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自带模块。

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

这个类是一个静态方法,通过异步发送邮件,防止线程阻塞。先加载线程锁,复制给第一个大类后在释放线程锁。达到了异步发送邮件的一个效果。

python 复制代码
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

文章原创首发于微信公众号 软件测试微课堂,更多内容欢迎关注微信公众号查看

相关推荐
Dnelic-9 小时前
解决 Android 单元测试 No tests found for given includes:
android·junit·单元测试·问题记录·自学笔记
岳哥i13 小时前
前端项目接入单元测试手册
前端·单元测试
qq_433716951 天前
Selenium+Pytest自动化测试框架 ------ 禅道实战
自动化测试·软件测试·selenium·单元测试·pytest·接口测试·压力测试
Dreams°1231 天前
【大数据测试ETL:从0-1实战详细教程】
大数据·数据仓库·python·单元测试·etl
敲代码敲到头发茂密1 天前
怎么做好白盒测试?
java·数据库·mysql·算法·单元测试·模块测试·测试覆盖率
安冬的码畜日常3 天前
【玩转 Postman 接口测试与开发2_007】第六章:Postman 测试脚本的创建(下):预请求脚本及环境变量在多个请求自动运行中的应用
测试工具·postman·测试·runner·api测试·自动测试
Dreams°1234 天前
【大数据测试HDFS + Flask详细教程与实例】
大数据·功能测试·hdfs·单元测试·flask
CSXB996 天前
三十八、Python(pytest框架-上)
python·功能测试·测试工具·单元测试·pytest
伍肆伍柒7 天前
SpringBoot 2.2.10 无法执行Test单元测试
spring boot·后端·单元测试
互联网杂货铺7 天前
基于Selenium+Python的web自动化测试框架(附框架源码+项目实战)
自动化测试·软件测试·python·selenium·测试工具·单元测试·测试用例