从零搭建完整 Python 接口自动化测试框架—持续更新

这篇具有很好参考价值的文章主要介绍了从零搭建完整 Python 接口自动化测试框架—持续更新。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本接口自动化框架采用 python + unittest + request + openpyxl + myddt + pymysql 来实现接口自动化。 

1、总体框架

python接口自动化环境搭建,API接口自动化,python,自动化

2、单元测试框架 unittest

unittest 是 Python 自带的一个单元测试框架

2.1 作用

  • 管理用例

  • 批量执行用例

  • 组织运行结果/报告

  • 让代码更稳健

  • 可拓展

2.2 unittest 框架中,有以下几个组件:

TestCase:即测试用例,Unittest提供testCase类来编写测试用例,一个TestCase的实例就是一个测试用例。一条测试用例就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown),通过运行一条测试用例,可以对某一个问题进行验证。

Fixture:即测试固件,用于测试用例环境的搭建和销毁。在测试步骤执行前需要为该测试用例准备环境(SetUp),如启动app或打开浏览器,测试步骤执行后需要恢复环境(TearDown),如关闭app或浏览器,这时候就需要用到Fixture,使代码更简洁。

TestSuite:即测试套件,把需要执行的测试用例集合在一起就是TestSuite。使用TestLoader来加载TestCase到TestSuite中

TextTestRunner:即测试执行器,用于执行测试用例。该模块中提供run方法执行TestSuite中的测试用例,并返回测试用例的执行结果,如运行的用例总数、用例通过数、用例失败数。

report:即测试报告。unittest框架没有自带的用于生成测试报告的模块或接口,需要使用第三方的扩展模块HTMLTestRunner。

2.3 跳过执行测试用例共有四种写法

  • @unittest.skip(reason) :跳过测试用例,reason  为测试被跳过的原因。
  • @unittest.skipIf(condition, reason) :当 condition 为真时,跳过测试用例。
  • @unittest.skipUnless(condition, reason) :跳过测试用例,除非 condition 为真。

2.4 断言

python接口自动化环境搭建,API接口自动化,python,自动化2.5 报告


from BeautifulReport import BeautifulReport
from common.HTMLTestRunnerNew import  HTMLTestRunner

# 4种测试报告
"""
1、生成 HTML 类型
2、生成 Br 类型
3、生成 txt 类型
"""
# ts0 = unittest.TestLoader().discover('test_cases')
# with open('reports/html_do接口自动化.html','wb') as f:
#     runner = HTMLTestRunner(f)
#     runner.run(ts0)
#
# ts1 = unittest.TestLoader().discover('test_cases')
# br = BeautifulReport(ts1)
# br.report(description='DO',filename='br_do接口自动化',report_dir='reports',theme='theme_memories')
#
#
# ts2 = unittest.TestLoader().discover('test_cases')
# with open('reports/txt_do接口自动化.txt','w+') as f:
#     unittest.TextTestRunner(f,2).run(ts2)



if __name__ == "__main__":
    unittest.main()

3、基础框架搭建

        在项目根目录下新建 common 文件夹,用来存储公用方法。

        在项目根目录下新建 reports 文件夹,用来存储项目报告。

        在项目根目录下新建 logs 文件夹,用来存储结果日志。

        在项目根目录下新建 test_data 文件夹,用来存储用例数据。

        在项目根目录下新建 test_cases 文件夹,用例存储测试用例模块。

        在项目根目录下新建 main.py 文件,作为入口函数,方便项目调试。

3.1 common公用方法文件

        3.1.1 init.py

# /usr/bin/env python
# __*__ coding: utf-8 __*__
# @Time : 2021/9/9 22:22
# @Author: 夜华


import settings
from common.log_handler import get_logger
from common.db_handler import DB

# 日志
logger = get_logger(**settings.LOG_CONFIG)

# 数据库
db = DB(settings.DB_CONFIG)

        3.1.2 http_requests.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 3:38 PM
@File : cliend_http_requests.py
@Project : PyCharm
"""
import requests

def cliend_http_requests(url,method,**kwargs):

    method = method.lower()

    return getattr(requests,method)(url,**kwargs)
if __name__ == "__main__":
    case = {
        'url' : 'http://10.21.5.74:33140/api/v1/login',
        'method' : 'post',
        'requests':{
            'json' : {"email": "name", "password": "password"},
            'headers' : {"Content-Type": "application/json;charset=UTF-8"}
        }
    }
    response = cliend_http_requests(url=case['url'],method=case['method'],**case['requests'])
    print(response.json())

        3.1.3 data_handler.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 4:10 PM
@File : data_handler.py
@Project : PyCharm
"""

import json
from openpyxl import load_workbook

def get_test_data(filename,sheet_name):
    wb = load_workbook(filename=filename)
    sh = wb[sheet_name]
    row = sh.max_row
    column = sh.max_column

    data = []
    keys = []

    for i in range(1,column+1):
        keys.append(sh.cell(1,i).value)

    for i in range(2,row+1):
        temp = {}
        for j in range(1,column+1):
            temp[keys[j-1]] = sh.cell(i,j).value
        try:
            temp['request'] = json.loads(temp['request'])
            temp['exportx_code'] = json.loads(temp['exportx_code'])
        except json.decoder.JSONDecodeError:
            raise ValueError('json数据转换错误')
        data.append(temp)
    return data


if __name__ == "__main__":
    res = get_test_data(filename='../test_data/test_cases.xlsx',sheet_name='login')
    print(res[0])

        3.1.4 db_handler.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 2:58 PM
@File : db_config_handler.py
@Project : PyCharm
"""
import settings
import pymysql

class DB:
    def __init__(self,db_config):
        self.conn = pymysql.connect(**db_config)

    def sql_one(self,sql):
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            return cursor.fetchone()


    def sql_many(self,sql,size=int):
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            return cursor.fetchmany(size)


    def sql_all(self,sql):
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            return cursor.fetchall()

    def exisx(self,sql):
        with self.conn.cursor() as cursor:
            cursor.execute(sql)
            if cursor.fetchone():
                return True
            else:
                return False

    def sql_update(self,sql):
        with self.conn.cursor() as cursor:
            try:
                cursor.execute(sql)
                self.conn.commit()
            except:
                self.conn.rollback()
            return cursor.fetchone()

    def __del__(self):
        self.conn.close()

if __name__ == "__main__":
    db = DB(db_config=settings.DB_CONFIG)

    print(db.sql_one("select * from help_category;"))

    print(db.sql_many("select * from help_category;",2))

    print(db.sql_all("select name from help_category;"))

    print(db.exisx("select * from help_category where name = 'Contents';"))

    print(db.sql_update("update help_category set url='' where name = 'Contents';"))

        3.1.5 fixtrue

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 8:27 PM
@File : fixtrue.py
@Project : PyCharm
"""

import requests
import settings
from common import logger

def login(email,password):
    data = {
        'email': email,
        'password': password
    }
    headers = {"Content-Type":"application/json;charset=UTF-8"}
    url =  settings.PROJECT_URL + settings.INTERFACE['login']

    res = requests.post(url=url,json=data,headers=headers)
    if res.status_code == 200:
        logger.info('用户登录成功')
        return res.json()
    else:
        logger.warning('用户登录失败')


if __name__ == "__main__":
    res = login(email='name',password='password')

        3.1.6 logs_handler.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 3:28 PM
@File : log_handler.py
@Project : PyCharm
"""
import logging

def get_logger(name,filename,debug=False,fmt=None,mode='w',encoding='utf-8'):

    logger = logging.getLogger(name=name)
    logger.setLevel(level=logging.DEBUG)

    if debug:
        file_level = logging.DEBUG
        console_level = logging.DEBUG
    else:
        file_level = logging.WARNING
        console_level = logging.INFO

    if fmt is None:
        #fmt = '%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d] - %(message)s'
        fmt = '%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s'


    format = logging.Formatter(fmt)
    file_handler = logging.FileHandler(filename=filename,mode=mode,encoding=encoding)
    file_handler.setLevel(level=file_level)

    console_handler = logging.StreamHandler()
    console_handler.setLevel(level=console_level)

    file_handler.setFormatter(format)
    console_handler.setFormatter(format)

    logger.addHandler(file_handler)
    logger.addHandler(console_handler)

    return logger

if __name__ == "__main__":
    logger = get_logger(name='do',filename='../logs/do.txt',debug=False,mode='a')
    logger.debug(10)
    logger.info(20)
    logger.warning(30)
    logger.error(40)
    logger.critical(50)

        3.1.7 reports_handler.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 3:42 PM
@File : reports_handler.py
@Project : PyCharm
"""


import os
from BeautifulReport import BeautifulReport
from common.HTMLTestRunnerNew import HTMLTestRunner
from  datetime import datetime

def reports(ts,filename,report_dir,theme='theme_default',title=None,description=None,tester=None,_type='br'):

    time_prefix=datetime.now().strftime('%Y-%m-%d_%H:%M')
    filename = '{}_{}'.format(time_prefix,filename)

    if _type == 'br':
        br = BeautifulReport(ts)
        br.report(description=description,filename=filename,report_dir=report_dir,theme=theme)

    else:
        with open(os.path.join(report_dir,filename),'wb') as f:
            runner = HTMLTestRunner(f,title=title,description=description,tester=tester)
            runner.run(ts)

4、config 配置文件夹

        4.1 config_dev.ini

[URL]
api_url = http://10.21.5.74:33140

        4.2 config_handler.py 

# /usr/bin/env python
# __*__ coding: utf-8 __*__
# @Time : 2021/9/10 21:00
# @Author: 夜华

"""
封装配置文件
"""
import yaml
from configparser import ConfigParser


def get_config(filename,encoding='utf-8'):
    # 根据 . 获取文件后缀,并获取后面的内容
    suffix = filename.split('.')[-1]

    if suffix in ['ini','cfg','cng']: # 判断文件后缀是否存在列表内
        # 就是ini 配置
        config = ConfigParser() # 实例
        config.read(filename,encoding=encoding) # 读取文件
        data = {} #
        for section in config.sections(): #获取 文件里面的所有段名
            data[section] = dict(config.items(section))
    elif suffix in ['yaml','yml']:
        # 就是 yaml 配置
        with open(filename,'r',encoding=encoding) as f:
            data = yaml.load(f,Loader=yaml.FullLoader)
    else:
        raise ValueError('不能识别的配置后缀')
    return data

if __name__ == '__main__':
    get = get_config('../config.ini')
    print(get)

    res = get_config('../config.yaml')
    print(res)

        4.3 init.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/6/1 2:18 PM
@File : __init__.py
@Project : PyCharm
"""

import os
import sys

from config.config_handler import get_config
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

if sys.argv[1] == "DEV":
    Config = get_config(os.path.join(BASE_DIR, './config_dev.ini'))
else:
    Config = get_config(os.path.join(BASE_DIR, './config_test.ini'))

5、 logs 文件夹

保存接口测试过程中输出的日志

 6、reports 文件夹

保存接口测试报告

7、test_cases 文件夹

        7.1 base_case.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 4:39 PM
@File : base_case.py
@Project : PyCharm
"""
import unittest
from common import logger,db
import requests
import settings


class Basic_test_case(unittest.TestCase):
    name = '基类'
    logger = logger
    requests = requests
    session = requests.session()
    db = db
    settings = settings

    @classmethod
    def setUpClass(cls) -> None:
        cls.logger.info('---------------【{}】开始测试---------------'.format(cls.name))

    @classmethod
    def tearDownClass(cls) -> None:
        cls.logger.info('---------------【{}】结束测试---------------'.format(cls.name))


    def check(self,case):
        self.logger.info('---------------【{}】开始测试---------------'.format(self.name))

        self.case = case # 测试用例
        self.step() # 测试步骤
        self.assert_status_code() # 断言状态码
        self.assert_json() # 断言响应信息
        self.assert_db() # 断言数据库是否存在数据


        self.logger.info('---------------【{}】结束测试---------------'.format(self.name))

    def step(self):
        self.case['url'] = self.settings.PROJECT_URL + self.settings.INTERFACE[self.case['url']]

        try:
            self.resposen = self.http_requests(url=self.case['url'],method=self.case['method'],**self.case['request'])
        except Exception as e:
            self.logger.warning('用例【{}】发送请求错误'.format(self.case['title']))
            self.logger.debug('url:【{}】'.format(self.case['url']))
            self.logger.debug('method:【{}】'.format(self.case['method']))
            raise e
        else:
            self.logger.info('用例【{}】发送请求成功'.format(self.case['title']))

    def assert_status_code(self):
        try:
            self.assertEqual(self.resposen.status_code,self.case['status_code'])
        except AssertionError as e:
            self.logger.warning('用例【{}】状态码断言错误'.format(self.case['title']))
            self.logger.debug('预期状态码:【{}】'.format(self.case['status_code']))
            self.logger.debug('实际状态码:【{}】'.format(self.resposen.status_code))
            raise e
        else:
            self.logger.info('用例【{}】状态码断言成功'.format(self.case['title']))

    def assert_json(self):
        res = self.resposen.json()

        res_data = {
            'phone':res.get('phone',None),
            'roleType':res.get('roleType',None)
        }

        try:
            self.assertEqual(res_data,self.case['exportx_code'])
        except AssertionError as e:
            self.logger.warning('用例【{}】响应信息断言错误'.format(self.case['title']))
            self.logger.debug('预期内容:【{}】'.format(self.case['exportx_code']))
            self.logger.debug('实际内容:【{}】'.format(res_data))
            self.logger.debug('响应内容:【{}】'.format(res))
            raise e
        else:
            self.logger.info('用例【{}】响应信息断言成功'.format(self.case['title']))


    def assert_db(self):
        if self.case.get('sql'):
            try:
                db_res = self.db.exisx(self.case['sql'])
                self.assertTrue(db_res)
            except Exception as e:
                self.logger.warning('用例【{}】数据库查询失败'.format(self.case['title']))
                self.logger.debug('sql:【{}】'.format(self.case['sql']))
                raise e
            else:
                self.logger.info('用例【{}】数据库查询成功'.format(self.case['title']))


    def http_requests(self,url,method,**kwargs)->requests.Response:
        method = method.lower()
        return getattr(self.session,method)(url=url,**kwargs)


if __name__ == "__main__":
    unittest.main()

        7.2 test_login.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 3:43 PM
@File : test_login.py
@Project : PyCharm
"""

import unittest
import settings
from test_cases.base_case import Basic_test_case
from common.data_handler import get_test_data
from common.myddt import data,ddt

cases = get_test_data(settings.TEST_DATA,sheet_name='login')



@ddt
class Test(Basic_test_case):
    name = '登录'

    @data(*cases)
    def test_01(self,case):
        self.check(case)

if __name__ == "__main__":
    unittest.main()

8、test_data 文件夹

        8.1 使用Excel表格维护测试用例

用例:id、title、url、method、requests、status_code、exportx_code、sql

python接口自动化环境搭建,API接口自动化,python,自动化

9、main.py

main.py 为 测试入口。


from BeautifulReport import BeautifulReport
from common.HTMLTestRunnerNew import  HTMLTestRunner

import settings
import unittest
from common.reports_handler import reports


ts = unittest.TestLoader().discover('test_cases')
runner = reports(ts,**settings.REPORTS_CONFIG)

if __name__ == "__main__":
    unittest.main()

10、settings.py

"""
-*- coding: utf-8 -*-
@Author : 夜华
@Time : 2023/5/14 2:53 PM
@File : settings.py
@Project : PyCharm
"""
import os

import project_api

BASE_DIR = os.path.dirname(os.path.abspath(__file__))


TEST_DATA = os.path.join(BASE_DIR,'test_data/test_cases.xlsx')


PROJECT_URL = 'http://10.00.5.74:00000'

INTERFACE = {
    'login' : '/api/v1/login',
    'query' : '/api/v1/approve/query?page=1&size=4294967295'
}


# 数据库配置
DB_CONFIG = {
    'user': 'root',
    'password': '123456',
    'host': '127.0.0.1',
    'database': 'mysql',
    'port': 3306,
    'autocommit': False
}

# 输出日志
LOG_CONFIG = {
    'name' : 'DPO',
    'filename' : os.path.join(BASE_DIR,'logs/dpo.txt'),
    'debug' : True,
    'mode' : 'w',
    'fmt' : None,
    'encoding': 'utf-8'
}

# 报告
REPORTS_CONFIG = {
    'filename':'do接口自动化',
    'report_dir' : os.path.join(BASE_DIR,'reports'),
    'theme' : 'theme_default',
    'description' : 'DO',
    'title': 'DO1期',
    '_type': 'br'
}

USER_LOGIN = {"email":"name","password":"password"}

11、终端内执行

python接口自动化环境搭建,API接口自动化,python,自动化注意:DEV表示开发环境,如果想在非开发环境进行测试,就输入TEST。也可以在4.3init.py 修改文章来源地址https://www.toymoban.com/news/detail-702438.html

到了这里,关于从零搭建完整 Python 接口自动化测试框架—持续更新的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何高效的学习接口自动化测试?从零开始学习接口自动化测试:选择合适的学习资源和编程语言

    目录 引言: 一、学习前的准备 二、选择合适的学习资源 三、实践中学习 四、总结 在日常的软件开发过程中,接口自动化测试是一个非常重要的环节。接口自动化测试可以帮助我们快速准确地检测出软件中的缺陷,提高软件的质量和稳定性。但是,要学习接口自动化测试并

    2024年02月06日
    浏览(68)
  • (Python)Requests+Pytest+Allure接口自动化测试框架从0到1搭建

    前面,已经学习了如何用SpringBoot写接口以及与Mysql数据库进行交互,具体可查阅下面的这篇博客,今天学习一下基于Python的接口自动化测试框架的搭建,主要包括以下内容:利用request库发送请求,请求数据参数化处理,还涉及到数据库(Mysql+MongDB)方面的交互,包括如何取数

    2024年02月13日
    浏览(161)
  • Postman 接口自动化测试教程:入门介绍和从 0 到 1 搭建 Postman 接口自动化测试项目

     关于Postman接口自动化测试的导引,全面介绍入门基础和从零开始搭建项目的步骤。学习如何有效地使用Postman进行API测试,了解项目搭建的基础结构、环境设置和测试用例的编写。无论您是新手还是经验丰富的测试人员,这篇教程都将为您提供清晰的指导,助您轻松构建强大

    2024年03月16日
    浏览(65)
  • 如何从零开始搭建自动化测试框架?详细步骤给到你

    目录 前言 1、确定需求 2、选择测试工具 3、选择编程语言 4、设计测试框架结构 5、编写测试用例 6、编写测试脚本 7、执行自动化测试 8、分析测试结果 9、设计测试用例 10、组织测试数据 11、选择开发工具 12、安排测试计划 13、提高测试覆盖率 总结 搭建自动化测试框架是一

    2023年04月09日
    浏览(68)
  • 接口自动化测试框架搭建【附详细搭建视频】

    如果遇到什么问题建议观看下面视频: 【敢称全站第一】B站最全的Python自动化测试深度学习教程!学完即就业,小白也能信手拈来!帮你少走99%的弯路~ 一、原理及特点 参数放在XML文件中进行管理 用httpClient简单封装一个httpUtils工具类 测试用例管理使用了testNg管理,使用了

    2024年02月07日
    浏览(49)
  • 【HttpRunnerManager】搭建接口自动化测试平台操作流程

    一、需要准备的知识点 1. linux: 安装 python3、nginx 安装和配置、mysql 安装和配置 2. python: django 配置、uwsgi 配置 二、我搭建的环境 1. Centos7 (配置 rabbitmq、mysql 、Supervisord) 2. python 3.6.8 (配置 django、uwsgi) 3. git 1.8.3.1 (克隆代码) 三、搭建过程 1. 配置数据库(安装 mysql ,自

    2024年02月10日
    浏览(71)
  • 接口自动化测试框架搭建【附教程加源码】

    1 接口测试 接口测试是对系统或组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。 接口自动化相对于UI自动化来说,属于更底层的测试,这样带来的好处就是测试收益更大,且维护成本相对来说较低,是我们进行自动化测试的

    2024年02月07日
    浏览(49)
  • JMeter+Ant+jenkins搭建接口自动化测试环境

    目录 前言:        1.ant简介 2. 构建ant环境 3.JMeter与Ant集成 4. 报告优化 5.jenkins持续集成 前言: JMeter是一个开源的性能测试工具,可以用于测试Web应用程序或API接口的性能,支持多种通信协议和数据格式。Ant是一个构建工具,可用于自动化构建、测试、打包和部署软件项目

    2024年02月09日
    浏览(52)
  • 基于 python 的接口自动化测试,让你轻松掌握接口自动化

    目录 目录 一、简介                ​编辑二、引言 三、环境准备 四、测试接口准备 接口信息 五、编写接口测试 六、优化 封装接口调用   本文从一个简单的登录接口测试入手,一步步调整优化接口调用姿势; 然后简单讨论了一下接口测试框架的要点; 最后介绍了一下

    2023年04月19日
    浏览(74)
  • 【jmeter+ant+jenkins】之搭建 接口自动化测试平台

           (1). 录制jmeter脚本   (2). 将jmeter的安装目录下的G:jmeterapache-jmeter-5.1.1extras中,将 ”ant-jmeter-1.1.1.jar”文件放到 ant的lib目录下   (3). 配置jmeter的xml配置文件,并放在ant目录的bin目录下,使用ant编译验证jmeter的build文件 build.xml文件 命令:Ant -buildfile build_jmeter.xml (

    2024年02月09日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包