• Python接口测试实战4(上)


    Python接口测试实战4(上) - 接口测试框架实战

     

    如有任何学习问题,可以添加作者微信:lockingfree

    课程目录

    Python接口测试实战1(上)- 接口测试理论
    Python接口测试实战1(下)- 接口测试工具的使用
    Python接口测试实战2 - 使用Python发送请求
    Python接口测试实战3(上)- Python操作数据库
    Python接口测试实战3(下)- unittest测试框架
    Python接口测试实战4(上) - 接口测试框架实战
    Python接口测试实战4(下) - 框架完善:用例基类,用例标签,重新运行上次失败用例
    Python接口测试实战5(上) - Git及Jenkins持续集成
    Python接口测试实战5(下) - RESTful、Web Service及Mock Server

    更多学习资料请加QQ群: 822601020获取

    本节内容

    • 数据分离 - 从Excel中读取数据
    • 增加log功能
    • 发送邮件
    • 使用配置文件
    • 框架整理

    上节课的框架雏形

    数据分离 - 从Excel中读取数据

    之前的用例中,数据直接写在代码文件里,不利于修改和构造数据
    这里我们使用Excel保存测试数据,实现代码和数据的分离
    新建Excel文件test_user_data.xlsx包含两个工作簿TestUserLoginTestUserReg,并复制到项目根目录下
    test_user_data.xlsx

    更新: excel表格中,增加一个headers列,内容为json格式, 如下

    TestUserLogin

    case_nameurlmethodheadersdataexpect_res
    test_user_login_normal http://115.28.108.130:5000/api/user/login/ POST {} {"name": "张三","password":"123456"} <h1>登录成功</h1>
    test_user_login_password_wrong http://115.28.108.130:5000/api/user/login/ POST {} {"name": "张三","password":"1234567"} <h1>失败,用户名或密码错误</h1>

    TestUserReg

    case_nameurlmethodheadersdataexpect_res
    test_user_reg_normal http://115.28.108.130:5000/api/user/login/ POST {} {"name": "范冰冰","password":"123456"} "{"code: "100000","msg": "成功,"data":
    test_user_reg_exist http://115.28.108.130:5000/api/user/login/ POST {} {"name": "张三","password":"123456"} "{"code": "100001","msg": "失败,用户已存在","data": {"name": "张三","password":"e10adc3949ba59abbe56e057f20f883e"}}"

    Excel读取方法:
    Python我们使用三方库xlrd来读取Excel

    安装方法: pip install xlrd

    import xlrd
    
    wb = xlrd.open_workbook("test_user_data.xlsx")  # 打开excel
    sh = wb.sheet_by_name("TestUserLogin")  # 按工作簿名定位工作表
    print(sh.nrows)  # 有效数据行数
    print(sh.ncols)  # 有效数据列数
    print(sh.cell(0, 0).value)  # 输出第一行第一列的值`case_name`
    print(sh.row_values(0))  # 输出第1行的所有值(列表格式)
    
    # 将数据和标题组装成字典,使数据更清晰
    print(dict(zip(sh.row_values(0), sh.row_values(1))))
    
    # 遍历excel,打印所有的数据
    for i in range(sh.nrows):
        print(sh.row_values(i))

    结果:

    3
    5
    case_name
    ['case_name', 'url', 'method', 'data', 'expect_res']
    {'case_name': 'test_user_login_normal', 'url': 'http://115.28.108.130:5000/api/user/login/', 'method': 'POST', 'data': '{"name": "张三","password":"123456"}', 'expect_res': '<h1>登录成功</h1>'}
    ['case_name', 'url', 'method', 'data', 'expect_res']
    ['test_user_login_normal', 'http://115.28.108.130:5000/api/user/login/', 'POST', '{"name": "张三","password":"123456"}', '<h1>登录成功</h1>']
    ['test_user_login_password_wrong', 'http://115.28.108.130:5000/api/user/login/', 'POST', '{"name": "张三","password":"1234567"}', '<h1>失败,用户不存在</h1>']

    封装读取excel操作:
    新建read_excel.py
    封装读取excel操作

    我们的目的是获取某条用例的数据,需要3个参数,excel数据文件名(data_file),工作簿名(sheet),用例名(case_name)
    如果我们只封装一个函数,每次调用(每条用例)都要打开一次excel并遍历一次,这样效率比较低。
    我们可以拆分成两个函数,一个函数excel_to_list(data_file, sheet),一次获取一个工作表的所有数据,另一个函数get_test_data(data_list, case_name)从所有数据中去查找到该条用例的数据。

    import xlrd
    
    def excel_to_list(data_file, sheet):
        data_list = []  # 新建个空列表,来乘装所有的数据
        wb = xlrd.open_workbook(data_file)  # 打开excel
        sh = wb.sheet_by_name(sheet)  # 获取工作簿
        header = sh.row_values(0)  # 获取标题行数据
        for i in range(1, sh.nrows):  # 跳过标题行,从第二行开始取数据
            d = dict(zip(header, sh.row_values(i)))  # 将标题和每行数据组装成字典
            data_list.append(d)
        return data_list  # 列表嵌套字典格式,每个元素是一个字典
    
    def get_test_data(data_list, case_name):
        for case_data in data_list:
            if case_name == case_data['case_name']:  # 如果字典数据中case_name与参数一致
                return case_data
                # 如果查询不到会返回None
    
    if __name__ == '__main__':   # 测试一下自己的代码
        data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 读取excel,TestUserLogin工作簿的所有数据
        case_data = get_test_data(data_list, 'test_user_login_normal')  # 查找用例'test_user_login_normal'的数据
        print(case_data)

    输出结果:

    {'case_name': 'test_user_login_normal', 'url': 'http://115.28.108.130:5000/api/user/login/', 'method': 'POST', 'data': '{"name": "张三","password":"123456"}', 'expect_res': '<h1>登录成功</h1>'}

    用例中使用方法
    test_user_login.py 部分

    import unittest
    import requests
    from read_excel import *  # 导入read_excel中的方法
    import json  # 用来转化excel中的json字符串为字典
    
    class TestUserLogin(unittest.TestCase):
        @classmethod
        def setUpClass(cls):   # 整个测试类只执行一次
            cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 读取该测试类所有用例数据
            # cls.data_list 同 self.data_list 都是该类的公共属性
    
        def test_user_login_normal(self):
            case_data = get_test_data(self.data_list, 'test_user_login_normal')   # 从数据列表中查找到该用例数据
            if not case_data:   # 有可能为None
                print("用例数据不存在")
            url = case_data.get('url')   # 从字典中取数据,excel中的标题也必须是小写url
            data = case_data.get('data')  # 注意字符串格式,需要用json.loads()转化为字典格式
            expect_res = case_data.get('expect_res')  # 期望数据
    
            res = requests.post(url=url, data=json.loads(data))  # 表单请求,数据转为字典格式
            self.assertEqual(res.text, expect_res)  # 改为assertEqual断言
    
    if __name__ == '__main__':   # 非必要,用于测试我们的代码
        unittest.main(verbosity=2)

    test_user_reg.py部分

    import unittest
    import requests
    from db import *
    from read_excel import *
    import json
    
    class TestUserReg(unittest.TestCase):
    
        @classmethod
        def setUpClass(cls):
            cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserReg")  # 读取TestUserReg工作簿的所有数据
    
        def test_user_reg_normal(self):
            case_data = get_test_data(self.data_list, 'test_user_reg_normal')
            if not case_data:
                print("用例数据不存在")
            url = case_data.get('url')
            data = json.loads(case_data.get('data'))  # 转为字典,需要取里面的name进行数据库检查
            expect_res = json.loads(case_data.get('expect_res'))  # 转为字典,断言时直接断言两个字典是否相等
            name = data.get("name")  # 范冰冰
    
            # 环境检查
            if check_user(name):
                del_user(name)
            # 发送请求
            res = requests.post(url=url, json=data)  # 用data=data 传字符串也可以
            # 响应断言(整体断言)
            self.assertDictEqual(res.json(), expect_res)
            # 数据库断言
            self.assertTrue(check_user(name))
            # 环境清理(由于注册接口向数据库写入了用户信息)
            del_user(name)
    
    if __name__ == '__main__':    # 非必要,用于测试我们的代码
        unittest.main(verbosity=2)  

    增加log功能

    新建config.py文件

    import logging
    
    logging.basicConfig(level=logging.DEBUG,  # log level
                        format='[%(asctime)s] %(levelname)s [%(funcName)s: %(filename)s, %(lineno)d] %(message)s',  # log格式
                        datefmt='%Y-%m-%d %H:%M:%S',  # 日期格式
                        filename='log.txt',  # 日志输出文件
                        filemode='a')  # 追加模式
    
    if __name__ == '__main__':
        logging.info("hello")

    运行后在当前目录下生成log.txt,内容如下:

    [2018-09-11 18:08:17] INFO [<module>: config.py, 38] hello

    Log Level:

    • CRITICAL: 用于输出严重错误信息
    • ERROR: 用于输出错误信息
    • WARNING: 用于输出警示信息
    • INFO: 用于输出一些提升信息
    • DEBUG: 用于输出一些调试信息

    优先级 CRITICAL > ERROR > WARNING > INFO > DEBUG
    指定level = logging.DEBUG所有等级大于等于DEBUG的信息都会输出
    若指定level = logging.ERROR WARNING,INFO,DEBUG小于设置级别的信息不会输出

    日志格式:

    • %(levelno)s: 打印日志级别的数值
    • %(levelname)s: 打印日志级别名称
    • %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
    • %(filename)s: 打印当前执行程序名
    • %(funcName)s: 打印日志的当前函数
    • %(lineno)d: 打印日志的当前行号
    • %(asctime)s: 打印日志的时间
    • %(thread)d: 打印线程ID
    • %(threadName)s: 打印线程名称
    • %(process)d: 打印进程ID
    • %(message)s: 打印日志信息

    项目使用log
    将所有print改为log,如db.py 部分

    import pymysql
    from config import *
    
    # 封装数据库查询操作
    def query_db(sql):
        conn = get_db_conn()
        cur = conn.cursor()  
        logging.debug(sql)    # 输出执行的sql
        cur.execute(sql)
        conn.commit()
        result = cur.fetchall() 
        logging.debug(result)  # 输出查询结果
        cur.close() 
        conn.close() 
        return result 
    
    # 封装更改数据库操作
    def change_db(sql):
        conn = get_db_conn() 
        cur = conn.cursor()
        logging.debug(sql)  # 输出执行的sql
        try:
            cur.execute(sql) 
            conn.commit() 
        except Exception as e:
            conn.rollback() 
            logging.error(str(e))  # 输出错误信息
        finally:
            cur.close() 
            conn.close()

    用例中使用

    import unittest
    import requests
    from read_excel import *  # 导入read_excel中的方法
    import json  # 用来转化excel中的json字符串为字典
    from config import *
    
    class TestUserLogin(unittest.TestCase):
        @classmethod
        def setUpClass(cls):   # 整个测试类只执行一次
            cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin")  # 读取该测试类所有用例数据
            # cls.data_list 同 self.data_list 都是该类的公共属性
    
        def test_user_login_normal(self):
            case_data = get_test_data(self.data_list, 'test_user_login_normal')   # 从数据列表中查找到该用例数据
            if not case_data:   # 有可能为None
                logging.error("用例数据不存在")
            url = case_data.get('url')   # excel中的标题也必须是小写url
            data = case_data.get('data')  # 注意字符串格式,需要用json.loads()转化为字典格式
            expect_res = case_data.get('expect_res')  # 期望数据
    
            res = requests.post(url=url, data=json.loads(data))  # 表单请求,数据转为字典格式
            logging.info("测试用例:{}".format('test_user_login_normal'))
            logging.info("url:{}".format(url))
            logging.info("请求参数:{}".format(data))
            logging.info("期望结果:{}".format(expect_res))
            logging.info("实际结果:{}".format(res.text)
            self.assertEqual(res.text, expect_res)  # 断言
    
    if __name__ == '__main__':
        unittest.main(verbosity=2)

    项目下log.txt输出结果:

    [2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 8] 测试用例:test_user_login_normal
    [2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 9] url:http://115.28.108.130:5000/api/user/login/
    [2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 10] 请求参数:{"name": "张三","password":"123456"}
    [2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 11] 期望结果:<h1>登录成功</h1>
    [2018-09-13 10:34:49] INFO [log_case_info: case_log.py, 12] 实际结果:<h1>登录成功</h1>

    因为每个用例都要输出很多log信息,我们封装一个case_log的函数

    项目下新建case_log.py

    from config import *
    import json
    
    def log_case_info(case_name, url, data, expect_res, res_text): 
        if isinstance(data,dict):
            data = json.dumps(data, ensure_ascii=False)  # 如果data是字典格式,转化为字符串
        logging.info("测试用例:{}".format(case_name))
        logging.info("url:{}".format(url))
        logging.info("请求参数:{}".format(data))
        logging.info("期望结果:{}".format(expect_res))
        logging.info("实际结果:{}".format(res_text)

    简化后的用例log输出

    import unittest
    import requests
    from read_excel import *  
    import json
    from config import *
    from case_log import log_case_info  # 导入方法
    
    class TestUserLogin(unittest.TestCase):
        @classmethod
        def setUpClass(cls):  
            cls.data_list = excel_to_list("test_user_data.xlsx", "TestUserLogin") 
    
        def test_user_login_normal(self):
            case_data = get_test_data(self.data_list, 'test_user_login_normal') 
            if not case_data: 
                logging.error("用例数据不存在")
            url = case_data.get('url')  
            data = case_data.get('data') 
            expect_res = case_data.get('expect_res')
    
            res = requests.post(url=url, data=json.loads(data))
            log_case_info('test_user_login_normal', url, data, expect_res, res_text)  # 输出用例log信息
            self.assertEqual(res.text, expect_res)  
    
    if __name__ == '__main__':
        unittest.main(verbosity=2)

    发送邮件

    在生成报告后我们希望框架能自动把报告发送到我们的邮箱中。和outlook,foxmail等邮件客户端一样,Python中发送邮件需要通过Email的smtp服务发送。

    首先需要确认用来发送邮件的邮箱是否启用了smtp服务

    发送邮件分3步

    1. 编写邮件内容(Email邮件需要专门的MIME格式)
    2. 组装Email头(发件人,收件人,主题)
    3. 连接smtp服务器并发送邮件
    import smtplib  # 用于建立smtp连接
    from email.mime.text import MIMEText  # 邮件需要专门的MIME格式
    
    # 1. 编写邮件内容(Email邮件需要专门的MIME格式)
    msg = MIMEText('this is a test email', 'plain', 'utf-8')  # plain指普通文本格式邮件内容
    
    # 2. 组装Email头(发件人,收件人,主题)
    msg['From'] = 'test_results@sina.com'  # 发件人
    msg['To'] = '2375247815@qq.com'  # 收件人
    msg['Subject'] = 'Api Test Report'  # 邮件主题
    
    # 3. 连接smtp服务器并发送邮件
    smtp = smtplib.SMTP_SSL('smtp.sina.com')  # smtp服务器地址 使用SSL模式
    smtp.login('自己的邮箱地址', '自己的邮箱密码')  # 用户名和密码
    smtp.sendmail("接收邮件地址1", "接收邮件地址2", msg.as_string())
    smtp.quit()

    中文邮件主题、HTML邮件内容,及附件

    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart  # 混合MIME格式,支持上传附件
    from email.header import Header  # 用于使用中文邮件主题
    
    # 1.  编写邮件内容
    with open('report.html', encoding='utf-8') as f:  # 打开html报告
        email_body = f.read()  # 读取报告内容
    
    msg = MIMEMultipart()  # 混合MIME格式
    msg.attach(MIMEText(email_body, 'html', 'utf-8'))  # 添加html格式邮件正文(会丢失css格式)
    
    # 2. 组装Email头(发件人,收件人,主题)
    msg['From'] = 'test_results@sina.com'  # 发件人
    msg['To'] = '2375247815@qq.com'  # 收件人
    msg['Subject'] = Header('接口测试报告', 'utf-8')  # 中文邮件主题,指定utf-8编码
    
    # 3. 构造附件1,传送当前目录下的 test.txt 文件
    att1 = MIMEText(open('report.html', 'rb').read(), 'base64', 'utf-8')  # 二进制格式打开
    att1["Content-Type"] = 'application/octet-stream'
    att1["Content-Disposition"] = 'attachment; filename="report.html"'  # filename为邮件中附件显示的名字
    msg.attach(att1)
    
    # 4. 连接smtp服务器并发送邮件
    smtp = smtplib.SMTP_SSL('smtp.sina.com')  # smtp服务器地址 使用SSL模式
    smtp.login('test_results@sina.com', 'hanzhichao123')  # 用户名和密码
    smtp.sendmail("test_results@sina.com", "2375247815@qq.com", msg.as_string())
    smtp.sendmail("test_results@sina.com", "superhin@126.com", msg.as_string())  # 发送给另一个邮箱
    smtp.quit()

    封装发送邮件方法

    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart  # 混合MIME格式,支持上传附件
    from email.header import Header  # 用于使用中文邮件主题
    from config import *
    
    
    def send_email(report_file):
        msg = MIMEMultipart()  # 混合MIME格式
        msg.attach(MIMEText(open(report_file, encoding='utf-8').read(), 'html', 'utf-8'))  # 添加html格式邮件正文(会丢失css格式)
    
        msg['From'] = 'test_results@sina.com'  # 发件人
        msg['To'] = '2375247815@qq.com'  # 收件人
        msg['Subject'] = Header('接口测试报告', 'utf-8')  # 中文邮件主题,指定utf-8编码
    
        att1 = MIMEText(open(report_file, 'rb').read(), 'base64', 'utf-8')  # 二进制格式打开
        att1["Content-Type"] = 'application/octet-stream'
        att1["Content-Disposition"] = 'attachment; filename="report.html"'  # filename为邮件中附件显示的名字
        msg.attach(att1)
    
        try:
            smtp = smtplib.SMTP_SSL('smtp.sina.com')  # smtp服务器地址 使用SSL模式
            smtp.login('test_results@sina.com', 'hanzhichao123')  # 用户名和密码
            smtp.sendmail("test_results@sina.com", "2375247815@qq.com", msg.as_string())
            smtp.sendmail("test_results@sina.com", "superhin@126.com", msg.as_string())  # 发送给另一个邮箱
            logging.info("邮件发送完成!")
        except Exception as e:
            logging.error(str(e))
        finally:
            smtp.quit()

    run_all.py中结束后发送邮件

    import unittest
    from HTMLTestReportCN import HTMLTestRunner
    from config import *
    from send_email import send_email
    
    logging.info("====================== 测试开始 =======================")
    suite = unittest.defaultTestLoader.discover("./")
    
    with open("report.html", 'wb') as f:  # 改为with open 格式
        HTMLTestRunner(stream=f, title="Api Test", description="测试描述", tester="卡卡").run(suite)
    
    send_email('report.html')  # 发送邮件
    logging.info("======================= 测试结束 =======================")

    测试邮件

    使用配置文件

    和项目的log配置一样,数据库服务器地址,邮件服务地址我们一般放到配置文件config.py

    import logging
    import os
    
    # 项目路径
    prj_path = os.path.dirname(os.path.abspath(__file__))  # 当前文件的绝对路径的上一级,__file__指当前文件
    
    data_path = prj_path  # 数据目录,暂时在项目目录下
    test_path = prj_path  # 用例目录,暂时在项目目录下
    
    log_file = os.path.join(prj_path, 'log.txt')  # 也可以每天生成新的日志文件
    report_file = os.path.join(prj_path, 'report.html')  # 也可以每次生成新的报告
    
    # log配置
    logging.basicConfig(level=logging.DEBUG,  # log level
                        format='[%(asctime)s] %(levelname)s [%(funcName)s: %(filename)s, %(lineno)d] %(message)s',  # log格式
                        datefmt='%Y-%m-%d %H:%M:%S',  # 日期格式
                        filename=log_file,  # 日志输出文件
                        filemode='a')  # 追加模式
    
    
    # 数据库配置
    db_host = '127.0.0.1'   # 自己的服务器地址
    db_port = 3306
    db_user = 'test'
    db_passwd = '123456'
    db = 'api_test'
    
    # 邮件配置
    smtp_server = 'smtp.sina.com'
    smtp_user = 'test_results@sina.com'
    smtp_password = 'hanzhichao123'
    
    sender = smtp_user  # 发件人
    receiver = '2375247815@qq.com'  # 收件人
    subject = '接口测试报告'  # 邮件主题

    修改db.py,send_email.pyrun_all.py等对配置文件的引用
    db.py部分

    import pymysql
    from config import *
    
    # 获取连接方法
    def get_db_conn():
        conn = pymysql.connect(host=db_host,   # 从配置文件中读取
                               port=db_port,
                               user=db_user,
                               passwd=db_passwd,  # passwd 不是 password
                               db=db,
                               charset='utf8')  # 如果查询有中文,需要指定测试集编码
    

    send_email.py

    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email.header import Header 
    from config import *
    
    
    def send_email(report_file):
        msg = MIMEMultipart()
        msg.attach(MIMEText(open(report_file, encoding='utf-8').read(), 'html', 'utf-8'))
    
        msg['From'] = 'test_results@sina.com'
        msg['To'] = '2375247815@qq.com'
        msg['Subject'] = Header(subject, 'utf-8')  # 从配置文件中读取
    
        att1 = MIMEText(open(report_file, 'rb').read(), 'base64', 'utf-8')  # 从配置文件中读取
        att1["Content-Type"] = 'application/octet-stream'
        att1["Content-Disposition"] = 'attachment; filename="{}"'.format(report_file)  # 参数化一下report_file
        msg.attach(att1)
    
        try:
            smtp = smtplib.SMTP_SSL(smtp_server)  # 从配置文件中读取
            smtp.login(smtp_user, smtp_password)  # 从配置文件中读取
            smtp.sendmail(sender, receiver, msg.as_string())
            logging.info("邮件发送完成!")
        except Exception as e:
            logging.error(str(e))
        finally:
            smtp.quit()

    run_all.py

    import unittest
    from HTMLTestReportCN import HTMLTestRunner
    from config import *
    from send_email import send_email
    
    logging.info("==================== 测试开始 =======================")
    suite = unittest.defaultTestLoader.discover(test_path)  # 从配置文件中读取用例路径
    
    with open(report_file, 'wb') as f:  # 从配置文件中读取
        HTMLTestRunner(stream=f, title="Api Test", description="测试描述").run(suite)
    
    send_email(report_file)  # 从配置文件中读取
    logging.info("==================== 测试结束 =======================")

    框架整理

    所有文件都在项目根目录
    当前所有文件(配置文件,公共方法,测试用例,数据,报告,log)都在项目根目录下,随着用例的增加和功能的补充,文件会越来越多,不便于维护和管理,因此我们要建立不同的文件夹,对文件进行分类组织

    1.在项目中新建以下文件夹:

    • config: 存放项目配置文件
    • data: 存放用例数据文件
    • lib: 公共方法库
    • log: 存放日志文件
    • report: 存放报告文件
    • test: 存放测试用例
      • user: 存放user模块用例 (模块下要有__init__.py,这样里面的用例才能读取到)

    2.将配置文件config.py移动到config目录下,将数据文件test_user_data.xlsx移动到data目录下,将公共方法db.py send_email.py case_log.py read_excel.py HTMLTestReportCN.py移动到lib目录下,将测试用例test_user_login.py test_user_reg.py移动到test/user目录下,保留run_all.py在项目根目录下,如图:
    整理后的项目结构

    3.修改配置文件
    config/config.py部分

    import logging
    import os
    
    # 项目路径
    prj_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 当前文件的上一级的上一级目录(增加一级)
    
    data_path = os.path.join(prj_path, 'data')  # 数据目录
    test_path = os.path.join(prj_path, 'test')   # 用例目录
    
    log_file = os.path.join(prj_path, 'log', 'log.txt')  # 更改路径到log目录下
    report_file = os.path.join(prj_path, 'report', 'report.html')  # 更改路径到report目录下

    4.修改对配置文件及公共方法的引用

    为避免相对路径导包出错的问题,我们统一把导包搜索路径(sys.path)提升到项目根目录下,如lib/db.py

    lib/db.py 部分

    import pymysql
    import sys
    sys.path.append('..')  # 提升一级到项目更目录下
    from config.config import *  # 从项目根目录下导入

    测试用例test_user_login.py部分

    import unittest
    import requests
    import json
    import os  # 增加了一个os,需要用来组装路径
    import sys
    sys.path.append("../..")  # 提升2级到项目根目录下
    from config.config import *  # 从项目路径下导入
    from lib.read_excel import *  # 从项目路径下导入
    from lib.case_log import log_case_info  # 从项目路径下导入
    
    class TestUserLogin(unittest.TestCase):
        @classmethod
        def setUpClass(cls):   # 整个测试类只执行一次
            cls.data_list = excel_to_list(os.path.join(data_path, "test_user_data.xlsx"),"TestUserLogin")  # 增加data路径

    run_all.py

    import unittest
    from lib.HTMLTestReportCN import HTMLTestRunner  # 修改导入路径
    from config.config import *  # 修改导入路径
    from lib.send_email import send_email  # 修改导入路径
    
    logging.info("================================== 测试开始 ==================================")
    suite = unittest.defaultTestLoader.discover(test_path)  # 从配置文件中读取
    
    with open(report_file, 'wb') as f:  # 从配置文件中读取
        HTMLTestRunner(stream=f, title="Api Test", description="测试描述").run(suite)
    
    send_email(report_file)  # 从配置文件中读取
    logging.info("================================== 测试结束 ==================================")
    
    1. 如果同一文件夹下的方法相互引用(如lib/read_excel.py假如需要引用lib/db.py),也需要采用这种从项目路径下导入的方式
    2. run_all.py直接在项目路径下,不需要提升sys.path,无需相对导入我们自己的包时,如read_excel.py,不需要提升

    5.运行run_all.py,根据log和报告调试代码,直至所有用例全部通过

    源码下载链接:https://pan.baidu.com/s/1RzwAlUMHwG4FQmeS-yB9rw 密码:rvq1

  • 相关阅读:
    浅析如何让 (a === 1 && a === 2 && a === 3) 返回 true
    浅析单点登录的三种实现方式
    浅析瀑布流布局原理及实现方式
    浅析Java中三目运算符可能产生的坑
    【转】IO
    [转]gomonkey学习
    从sha1的计算例子,理解计算机的数据表示?16进制输出?二进制输出??
    [转]Golang第三方包应该如何安装--在线和离线
    【转】goconvey使用
    go import 时 点号 和下划线的区别
  • 原文地址:https://www.cnblogs.com/yuany66/p/11477188.html
Copyright © 2020-2023  润新知