zoukankan      html  css  js  c++  java
  • Python接口测试课程(第四天)-接口测试框架实现

    目录

    Python接口测试课程(第一天)-Python基础
    Python接口测试课程(第二天)-接口测试快速实践
    Python接口测试课程(第三天)-接口安全验证,参数化及断言
    Python接口测试课程(第四天)-接口测试框架实现

    PDF下载:链接:https://pan.baidu.com/s/1x3_LYq23F_1LviGVbRNFXw 密码:xrcj

    更多学习资料请加添加作者微信:lockingfree获取

    第四天: Python接口测试框架

    什么是框架

    目前主流接口测试方案

    • 工具派
    • Java派
    • Python派
    • 接口平台

    框架类型

    • 录制回放
    • 数据驱动
    • 行为驱动

    框架的分层与规划

    框架分层

    • 表示层: (用户界面)
    • 业务逻辑层: (读取数据,配置并组装发送请求)+执行控制层(pytest)
    • 数据层: (配置读取/数据读取/数据库连接/其他(log/email)

    框架规划

    • case: 测试用例目录
      • user: (用户模块)
        • test_user.py: 测试用例
      • case.py: 用例公共方法
    • data: 数据文件目录
      • test_user_data.xlsx: 测试用例数据文件
    • conf: 配置文件目录
      • default.conf: 默认配置文件
    • report: pytest生成的报告保存路径
    • log: log保存路径,按天生成log
    • common: 公共方法目录
      • config.py: 配置文件读取
      • data.py: 数据文件读取
      • db.py: 数据库连接
      • log.py: 日志配置
      • send_email.py: 发送邮件配置

    框架实现

    conf/default.conf: 表示层-项目配置文件

    [runtime]
    log_level=debug
    report_dir=report
    log_dir=log
    timeout=10
    
    [server]
    test = http://127.0.0.1:5000
    stage = http://127.0.0.1:6000
    prod = http://127.0.0.1:7000
    
    [db_test]
    host = localhost
    port = 3307
    db = api
    user = root
    passwd = 
    
    [db_stage]
    
    [db_prod]
    
    [email]
    server = smtp.sina.com
    user = test_results@sina.com
    pwd =  ******
    subject = Api Test Ressult
    receiver = superhin@126.com
    

    data/test_user_data.xlsx: 表示层-用例数据文件

    • reg表(sheet名为reg)
    TestCase Url Method DataType Data Code Msg
    test_reg_normal /api/user/reg/ POST JSON {"name": "{NAME}", "passwd": "123456"} 100000 成功
    • login表(sheet名为login)
    TestCase Url Method DataType Data ResponseText
    test_login_normal /api/user/login/ POST FORM {"name": "张三", "passwd": "123456"} 登录成功
    • SQL表(sheet名为SQL)
    checkUser select * from user where name={NAME}
    checkUserPasswd select * from user where name={NAME} and passwd={PASSWD}

    common/config.py:数据层-config文件读取

    """
    1. 从配置文件中获取各个段信息
    2. 返回一个项目的绝对路径
    """
    import os
    import configparser
    
    # 相对导入包的问题
    
    pro_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    
    class Config(object):
        def __init__(self, filename="default.conf"):
            self.cf = configparser.ConfigParser()
            self.cf.read(os.path.join(pro_path,"conf",filename))
            
        def get_runtime(self, option):
            return self.cf.get("runtime", option)
    
        def get_server(self, option):
            return self.cf.get("server", option)
    
        def get_db_test(self, option):
            return self.cf.get("db_test", option)
    
        def get_email(self, option):
            return self.cf.get("email",option)
    
    if __name__ == "__main__":
        c = Config()
        print(c.get_runtime("log_level"))
        print(c.get_server("test"))
    

    data.py: 数据层-数据文件读取

    """
    1. 从Excel中读取接口的数据
    2. 读取Sql命令
    """
    import xlrd
    import sys
    import os
    sys.path.append("..")
    from common.config import pro_path
    
    class Data(object):
        def __init__(self, filename):
            data_file_path = os.path.join(pro_path,"data",filename)   
            self.wb = xlrd.open_workbook("../data/test_user_data.xlsx")
    
        def get_case(self,sheet_name, case_name):
            sh = self.wb.sheet_by_name(sheet_name)
            for i in range(1, sh.nrows):
                if sh.cell(i,0).value == case_name:
                    return sh.row_values(i)
    
            print("用例名未找到")
            return None
    
        def get_sql(self, sql_name):
            sh = self.wb.sheet_by_name("SQL")
            for i in range(sh.nrows):
                if sh.cell(i,0).value == sql_name:
                    return sh.cell(i,1).value
            print("sql未找到")
            return None
    
    if __name__ == "__main__":
        d = Data("test_user_data.xlsx")
        print(d.get_case("reg","test_reg_normal"))
        print(d.get_sql("checkUser"))
    

    db.py: 数据层-数据库连接

    """
    1. 从配置文件中读取数据库配置
    2. 连接数据库
    3. 执行sql并返回所有结果
    """
    import sys
    import pymysql
    sys.path.append("..")
    from common.config import Config
    
    class DB(object):
        def __init__(self):
            c = Config()
            self.conn = pymysql.connect(host=c.get_db_test("host"),
                                        port=int(c.get_db_test("port")),
                                        db=c.get_db_test("db"),
                                        user=c.get_db_test("user"),
                                        passwd=c.get_db_test("passwd"),
                                        charset="utf8")
    
            self.cur = self.conn.cursor()
    
        def do_sql(self, sql):
            self.cur.execute(sql)
            return self.cur.fetchall()
    
        def __del__(self):
            self.cur.close()
            self.conn.close()
    
    if __name__ == "__main__":
        db = DB()
        print(db.do_sql("select * from user"))
    
    

    log.py: 数据层-log配置

    """
    1. 配置log输出格式 time - loglevel - file - func - line - msg
    2. 支持输出到log文件及屏幕
    3. 支持返回一个logger,让其他模块调用
    """
    import sys
    sys.path.append("..")
    
    from common.config import Config, pro_path
    import time
    import logging
    import os
    
    class Log():
        @classmethod
        def config_log(cls):
            cf = Config()
            log_dir = os.path.join(pro_path, cf.get_runtime("log_dir"))
            today = time.strftime("%Y%m%d", time.localtime(time.time()))
            log_file = os.path.join(log_dir, today+".log")
    
            # 获取一个标准的logger, 配置loglevel
            cls.logger = logging.getLogger()
            cls.logger.setLevel(eval("logging." + cf.get_runtime("log_level").upper()))
    
            # 建立不同handler
            fh = logging.FileHandler(log_file, mode="a",encoding=‘utf-8’)
            ch = logging.StreamHandler()
    
            # 定义输出格式
            ft = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
            fh.setFormatter(ft)
            ch.setFormatter(ft)
    
            # 把定制handler 添加到我们logger
            cls.logger.addHandler(fh)
            cls.logger.addHandler(ch)
    
        @classmethod
        def get_logger(cls):
            cls.config_log()
            return cls.logger
    
    if __name__ == "__main__":
        l= Log.get_logger()
        l.info("abc")
        l.debug("hello, debug")
    

    send_email.py: 数据层-邮件服务器连接

    """
    1. 从配置文件中读取stmp配置
    2. 从report文件夹下打开report.html,发送邮件
    """
    import smtplib
    from email.mime.text import MIMEText
    import os
    import sys
    sys.path.append("..")
    from common.config import Config, pro_path
    from common.log import Log
    
    
    def send_email(report_name):
        cf = Config()
        logger = Log.get_logger()
        report_file = os.path.join(pro_path, cf.get_runtime("report_dir"),report_name)
    
        with open(report_file, "rb") as f:
            body = f.read()
    
        # 格式化email正文
        msg = MIMEText(body, "html", "utf-8")
    
        # 配置email头
        msg["Subject"] = cf.get_email("subject")
        msg["From"] = cf.get_email("user")
        msg["To"] = cf.get_email("receiver")
    
        
        # 连接smtp服务器,发送邮件
        smtp = smtplib.SMTP()
        smtp.connect(cf.get_email("server"))
        smtp.login(cf.get_email("user"),cf.get_email("pwd"))
        smtp.sendmail(cf.get_email("user"), cf.get_email("receiver"), msg.as_string())
        print("邮件发送成功")
    
    if __name__ == "__main__":
        send_email("report.html")
    

    case/case.py: 业务逻辑层, 为用例执行封装方法

    """
    1. 加载数据
    2. 发送接口
    3. 为用例封装一些方法
    
    """
    import sys
    sys.path.append("..")
    from common.log import Log
    from common.config import Config
    from common.db import DB
    from common.data import Data
    import json
    import requests
    
    
    class Case(object):
        def __init__(self):
            self.logger = Log.get_logger()
            self.cf = Config()
    
        def load_data(self, data_file):
            self.data = Data(data_file)
    
        def set_env(self, env):
            self.env = env
    
        def run_case(self, sheet_name, case_name, var={}):
            case_data = self.data.get_case(sheet_name, case_name)
    
            url = self.cf.get_server(self.env) + case_data[1]
            data = case_data[4].format(**var)
            
            if case_data[3].lower() == "form":
                data = json.loads(data)
                headers = {}
            else:
                headers = {"content-type": "application/json"}
    
            if case_data[2].lower() == "get":
                resp = requests.get(url=url)
            else:
                resp = requests.post(url=url, headers=headers, data=data)
            return resp.text
            
        def check_response(self):
            pass
        
        def check_db(self, sql_name, vars={}):
            sql = self.data.get_sql(sql_name).format(**vars)
            return self.db.exec_sql(sql)
            
    
    if __name__ == "__main__":
        c = Case()
        c.set_env("test")
        c.load_data("test_user_data.xlsx")
        r = c.run_case("login", "test_login_normal")
        print(r)
    

    case/user/test_user.py: 表示层: 测试用例脚本

    import sys
    import random
    import pytest
    sys.path.append("../..")
    from case.case import Case
    
    case = Case()
    
    def setup_module(module):
        case.set_env('dev')
        case.load_data('test_user_data.xlsx')
    
    def test_login_normal():
        result case.run("login", "test_login_normal")
    
    if __name__ == '__main__':
        pytest.main(["-q", "test_user.py"])
    

    run_all.py: 表示层: 执行所有用例入口

    import os
    import time
    from util.config import Config
    from util.e_mail import send_email
    import pytest
    
    def main():
        cf = Config()
        report_dir = cf.get_report_dir()
        now = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        report_name = os.path.join(report_dir, 'report_' + now + '.html')
        pytest.main(["-q", "case", "--html=" + report_name])
        send_email(report_name)
    
    if __name__ == '__main__':
        main()
    
  • 相关阅读:
    HDU2438:Turn the corner(三分)
    XTU1267:Highway(LCA+树的直径)
    HDU6024:Building Shops(DP)
    “玲珑杯”ACM比赛 Round #13 B -- 我也不是B(二分排序)
    XTU1266:Parentheses(贪心+优先队列)
    Educational Codeforces Round 21 D
    Educational Codeforces Round 21E selling souvenirs (dp)
    EOJ3247:铁路修复计划
    关于工厂模式的 个人理解
    设计模式之 工厂方法
  • 原文地址:https://www.cnblogs.com/superhin/p/12737710.html
Copyright © 2011-2022 走看看