一、什么是Mock测试
概念
在接口测试中,对于某些不容易构造 或者不容易获取 的接口,用一个模拟接口来代替。
作用
| 作用 | 说明 |
|---|---|
| 解除依赖 | 解除对外部服务的依赖,不受第三方接口限制 |
| 模拟异常 | 模拟正常/异常场景(如超时、返回错误码) |
| 提前测试 | 后端接口未开发完成时,前端/测试可先模拟接口进行调试 |
解决的核心问题
后端合同删除代码未开发完,测试工作如何开展?
❌ 待开发完成之后再测(浪费时间)
✅ 模拟后端代码继续测试(Mock)
二、Mock实现方式
| 方式 | 说明 | 适用场景 |
|---|---|---|
| 第三方Mock平台 | 如YApi、EasyMock | 团队协作,可视化配置 |
| Mock框架 | 如Moco(Java)、MockServer | 本地搭建,灵活配置 |
| 自己开发Mock服务 | 如Flask(Python) | 定制化需求,完全可控 |
三、Moco框架
1. 介绍
-
Moco:一个简单搭建模拟服务器的框架(工具)
-
支持协议:HTTP、HTTPS、Socket等
-
开发语言:基于Java开发的开源项目
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 | 让你重复使用连接,不用每次都重新连接 |