接口Mock测试

一、什么是Mock测试

概念

在接口测试中,对于某些不容易构造 或者不容易获取 的接口,用一个模拟接口来代替。

作用

作用 说明
解除依赖 解除对外部服务的依赖,不受第三方接口限制
模拟异常 模拟正常/异常场景(如超时、返回错误码)
提前测试 后端接口未开发完成时,前端/测试可先模拟接口进行调试

解决的核心问题

后端合同删除代码未开发完,测试工作如何开展?

  • ❌ 待开发完成之后再测(浪费时间)

  • ✅ 模拟后端代码继续测试(Mock)


二、Mock实现方式

方式 说明 适用场景
第三方Mock平台 如YApi、EasyMock 团队协作,可视化配置
Mock框架 如Moco(Java)、MockServer 本地搭建,灵活配置
自己开发Mock服务 如Flask(Python) 定制化需求,完全可控

三、Moco框架

1. 介绍

  • Moco:一个简单搭建模拟服务器的框架(工具)

  • 支持协议:HTTP、HTTPS、Socket等

  • 开发语言:基于Java开发的开源项目

  • GitHubhttps://github.com/dreamhead/moco

2. 原理

  • 根据配置文件,启动一个真正的HTTP服务

  • 监听本地的某个端口

  • 当发起的请求满足某个条件时,返回指定的响应数据

3. 环境搭建

步骤 说明
① 安装JDK Java运行环境,配置环境变量
② 下载jar包 moco-runner-1.1.0-standalone.jar
下载地址 https://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/1.1.0/

4. 快速入门

步骤1:创建配置文件(test.json)
复制代码
[
  {
    "description": "首页",
    "request": {
      "uri": "/index"
    },
    "response": {
      "text": "hello world"
    }
  }
]
步骤2:启动HTTP服务
复制代码
java -jar moco-runner-1.1.0-standalone.jar http -p 9090 -c test.json

参数说明:

参数 说明
http 协议类型
-p 9090 监听端口号
-c test.json 配置文件路径
步骤3:访问接口

浏览器打开:http://localhost:9090/index


四、Moco常用配置参数

请求参数(request)

参数 作用 示例
method 定义请求方法 "method": "post"
uri 定义请求路径 "uri": "/api/login"
queries 定义查询参数 "queries": {"area": "010"}
headers 定义请求头 "headers": {"Content-Type": "application/json"}
forms 定义表单请求体 "forms": {"username": "tom"}
json 定义JSON请求体 "json": {"username": "admin"}

响应参数(response)

参数 作用 示例
status 定义HTTP响应状态码 "status": 200
json 定义JSON响应数据 "json": {"msg": "操作成功"}
text 定义文本响应 "text": "hello"
headers 定义响应头 "headers": {"Content-Type": "application/json"}

五、Moco完整案例

登录接口Mock配置(login.json)

复制代码
[
  {
    "description": "登录",
    "request": {
      "uri": "/api/login",
      "method": "post",
      "headers": {"Content-Type": "application/json"},
      "json": {"username": "admin", "password": "admin123", "code": "2", "uuid": "xxx"}
    },
    "response": {
      "status": 200,
      "headers": {"Content-Type": "application/json;charset=utf-8"},
      "json": {"msg": "操作成功", "code": "200", "token": "xxxxxx"}
    }
  }
]

启动命令

复制代码
java -jar moco-runner-1.1.0-standalone.jar http -p 9090 -c login.json

Python调用Mock接口

复制代码
import requests
​
response = requests.post(
    "http://127.0.0.1:9090/api/login",
    json={"username": "admin", "password": "admin123", "code": "2", "uuid": "xxx"}
)
​
print(response.json())  # {'msg': '操作成功', 'code': '200', 'token': 'xxxxxx'}
print(response.status_code)  # 200

六、Python + Flask 开发Mock服务

1. Flask介绍

  • Flask:Python编写的轻量级Web应用程序框架

  • 可以非常方便地开发Web项目(Mock服务)

2. 环境搭建

复制代码
pip install Flask

3. 快速入门(flask_demo.py)

复制代码
from flask import Flask
​# 创建一个应用对象
app = Flask(__name__)
​# 定义视图函数,设置路由规则
@app.route("/index")
def index():
    return "hello world."
​# 启动web服务器
if __name__ == '__main__':
    app.run()

4. 启动服务

复制代码
python flask_demo.py

访问:http://127.0.0.1:5000/index

5. Flask 框架写的 Mock 服务

复制代码
from flask import Flask, request, jsonify
import json

app = Flask(__name__)

# GET请求 + 查询参数
@app.route('/api/search', methods=['GET'])
def search():
    args = request.args
    name = args.get('name')
    age = args.get('age')
    return f"name={name} age={age}"

# POST请求 + JSON参数
@app.route("/api/add", methods=["POST"])
def add():
    data = request.get_json()  # 获取JSON请求体
    a = data.get("a")
    b = data.get("b")
    
    if 0 <= a <= 99 and 0 <= b <= 99:
        return {"a": a, "b": b, "result": a + b}
    else:
        return {"a": a, "b": b, "result": "Input error."}

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

6. Flask接口调用示例

复制代码
import requests

# GET请求
resp = requests.get("http://127.0.0.1:5000/api/search?name=张三&age=20")
print(resp.text)  # name=张三 age=20

# POST请求
resp = requests.post(
    "http://127.0.0.1:5000/api/add",
    json={"a": 10, "b": 20}
)
print(resp.json())  # {'a': 10, 'b': 20, 'result': 30}

七、Mock vs 真实接口对比

对比项 Mock接口 真实接口
开发状态 未完成/不可用 已完成
返回数据 固定的预设数据 真实的业务数据
异常模拟 可以任意模拟 难以构造
外部依赖 无依赖 依赖第三方服务
执行速度 极快 受网络/数据库影响
维护成本 需同步更新 自动同步

八、Moco vs Flask 对比

对比项 Moco Flask
语言 Java Python
配置方式 JSON配置文件 Python代码
灵活性 较低(仅配置) 高(可写逻辑)
学习成本 低(JSON格式) 中(需懂Python)
启动方式 java -jar命令 python脚本
适用场景 简单Mock 复杂Mock(有计算逻辑)
复制代码
from flask import Flask, request, jsonify
import json
import random
import string

app = Flask(__name__)

# 模拟用户数据
users = {
    "admin": "HM_2023_test",
    "manager": "123456"
}

# 存储验证码的字典(实际项目中应该使用redis等缓存)
captcha_dict = {}


@app.route('/c', methods=['GET']) 
def get_captcha():
    """生成验证码接口"""
    # 生成随机的uuid和验证码
    uuid = ''.join(random.choices(string.ascii_lowercase + string.digits, k=32))
    code = "1234"

    # 存储到字典中,实际项目中应该设置过期时间
    captcha_dict[uuid] = code
    print(f"[DEBUG] uuid: {uuid}, code: {code}")

    # 生成base64编码的图片数据(简化处理)
    img_data = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="

    return jsonify({
        "msg": "操作成功",
        "img": img_data,
        "code": 200,
        "uuid": uuid
    })


@app.route('/api/login', methods=['POST'])
def login():
    """登录接口"""
    data = request.get_json()

    username = data.get('username')
    password = data.get('password')
    code = data.get('code')
    uuid = data.get('uuid')

    # 验证参数是否完整
    if not all([username, password, code, uuid]):
        return jsonify({
            "msg": "缺少必填参数",
            "code": 500
        }), 200

    # 验证码校验
    if uuid not in captcha_dict or captcha_dict[uuid] != code:
        return jsonify({
            "msg": "验证码已失效",
            "code": 500
        }), 200

    # 用户名密码校验
    if username not in users or users[username] != password:
        return jsonify({
            "msg": "用户名或密码错误",
            "code": 500
        }), 200

    # 登录成功,生成token
    token = ''.join(random.choices(string.ascii_letters + string.digits, k=32))

    return jsonify({
        "msg": "操作成功",
        "code": 200,
        "token": token
    }), 200


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000, debug=True)

九、一句话总结

Mock测试 = 模拟接口。后端没写好时,测试可以先用Moco或Flask自己搭一个假的接口,不耽误测试进度。

Apifox启动mock

DBUtils

一、是什么

DBUtils = 数据库操作工具包

版本 核心作用
Java版 简化JDBC代码,让数据库操作更简单
Python版 管理数据库连接池,避免频繁创建连接

二、Java版 DBUtils

作用

不用写一堆 try-catch-finally,几行代码搞定数据库操作

核心类

作用
QueryRunner 执行SQL(增删改查)
ResultSetHandler 处理查询结果,转成对象

使用步骤

复制代码
// 1. 创建执行器
QueryRunner qr = new QueryRunner();
​
// 2. 执行增删改
qr.update(conn, "insert into student values(?,?)", "张三", 20);
​
// 3. 执行查询(结果转对象)
Student stu = qr.query(conn, "select * from student where id=?", 
                       new BeanHandler<>(Student.class), 1);

三、Python版 DBUtils

作用

创建数据库连接池,复用连接,不用每次都重新连

使用步骤

复制代码
from dbutils.pooled_db import PooledDB
import pymysql
​
# 1. 创建连接池
pool = PooledDB(
    creator=pymysql,  # 驱动
    host='localhost',
    user='root',
    password='123456',
    database='test'
)
​
# 2. 从池子里拿连接
conn = pool.connection()
cursor = conn.cursor()
​
# 3. 执行SQL
cursor.execute("select * from student")
​
# 4. 归还连接(不是关闭)
cursor.close()
conn.close()
复制代码
import pymysql


class DBUtil:
    # 初始化
    __conn = None
    __cursor = None

    # 创建连接
    @classmethod
    def __get_conn(cls):
        if cls.__conn is None:
            cls.__conn = pymysql.connect(host="192.168.64.130",
                                         port=3306,
                                         user="root",
                                         password="123456",
                                         database="litemall",
                                         charset="utf8")
        return cls.__conn

    # 创建游标
    @classmethod
    def __get_cursor(cls):
        if cls.__cursor is None:
            cls.__cursor = cls.__get_conn().cursor()
        return cls.__cursor

    # 执行sql
    @classmethod
    def exe_sql(cls, sql):
        try:
            cursor = cls.__get_cursor()
            cursor.execute(sql)
            if sql.split()[0].lower() == "select":
                return cursor.fetchall()
            else:
                cls.__conn.commit()
                return cursor.rowcount
        except Exception as e:
            print(e)
            cls.__conn.rollback()
        finally:
            cls.__close_cursor()
            cls.__close_conn()

    # 关闭游标
    @classmethod
    def __close_cursor(cls):
        if cls.__cursor:
            cls.__cursor.close()
            cls.__cursor = None

    # 关闭连接
    @classmethod
    def __close_conn(cls):
        if cls.__conn:
            cls.__conn.close()
            cls.__conn = None


if __name__ == '__main__':
    # 查看数据库服务器版本
    sql = "select version();"
    print(DBUtil().exe_sql(sql))  # 5.7.36

# 导包
from dbutil import DBUtil


# 查询服务器版本
sql = "select * from litemall_user"
print(DBUtil().exe_sql(sql))

# 查询项目用户表中数据
# 获取1行数据
# 获取所有数据
# 获取多行数据

四、一句话总结

版本 一句话
Java DBUtils 让你少写代码,轻松操作数据库
Python DBUtils 让你重复使用连接,不用每次都重新连接
相关推荐
qq_白羊座2 小时前
Langchain、Cursor、python的关系
开发语言·python·langchain
kiku18182 小时前
Python网络编程
开发语言·网络·python
zncxCOS2 小时前
【ETestDEV5教程30】ICD操作之信号组操作
python·测试工具·测试用例·集成测试
智购科技自动售货机2 小时前
自动贩卖机厂家哪家价格公道
人工智能·python
Thomas.Sir2 小时前
智能革命:AI如何重塑金融风控与信贷审批的底层逻辑
人工智能·python·ai·风控
流星蝴蝶没有剑2 小时前
CoPaw Agent 对接 Python 客户端开发指南:实现流式响应与实时打印
开发语言·python
小陈工2 小时前
Python Web开发入门(十八):跨域问题解决方案——从“为什么我的请求被拦了“到“我让浏览器乖乖听话“
开发语言·python·机器学习·架构·数据挖掘·回归·状态模式
赵优秀一一2 小时前
Python 工程化基础1:环境(conda)、pip、requirements.txt
linux·开发语言·python
kaizq2 小时前
Python-Nacos电商订单分布微服系统开发
python·nacos·分布微服务·ai-ima-glm·电商订单