内容社区系统开发文档(下)
目录
4 系统测试
4.1 数据库测试设计
测试流程图
测试策略矩阵
4.2 数据库测试内容
测试点 1:数据项增删改查(CRUD)操作 和 数据一致性测试
一、基础数据初始化
二、用户表测试(users)
1. 新增用户
2. 更新用户信息
3. 删除用户
三、内容表测试(contents)
1. 发布内容
2. 更新内容
3. 删除内容(级联验证)
四、评论系统测试(comments)
1. 发表评论
2. 逻辑删除评论
3. 物理删除评论
五、互动系统测试(interactions)
1. 点赞内容
2. 取消点赞(删除互动记录)
3. 收藏内容(唯一性约束测试)
六、关注系统测试(follows)
1. 关注用户
2. 取消关注
3. 统计粉丝数和关注数(通过存储过程)
1. 新增标签
2. 关联内容和标签
3. 删除标签(级联删除关联关系)
八、存储过程与函数测试
九、触发器完整性验证
1. 验证互动触发器
2. 验证评论逻辑删除触发器
十、异常场景测试
1. 外键约束失败
测试点 2:数据表的并发操作
测试点 3:边界条件测试(表满 / 空状态)
测试点4:针对存储过程的接口测试
测试点5:结合业务逻辑做关联表的接口测试
4 系统测试
4.1 数据库测试设计
测试流程图
测试策略矩阵
测试类型 | 测试目标 | 测试工具/方法 |
---|---|---|
功能测试 | CRUD操作有效性验证 | SQL脚本 |
性能测试 | 高并发场景稳定性验证 | ThreadPoolExecutor |
数据完整性 | 级联删除/触发器验证 | 事务回滚测试 |
容错测试 | 无效数据插入/空表操作 | 边界值测试 |
4.2 数据库测试内容
测试点 1:数据项增删改查(CRUD)操作 和 数据一致性测试
测试内容:验证用户表、内容表等表的数据增删改查功能。 验证外键约束、触发器逻辑是否保证数据一致性(如删除内容时级联删除关联评论)。
一、基础数据初始化
-- ----------------------------
-- 一、基础数据初始化
-- ------------------------------ 插入测试用户
INSERT INTO users (username, email, password_hash)
VALUES
('test_user1', 'user1@example.com', SHA2('password1', 256)),
('test_user2', 'user2@example.com', SHA2('password2', 256));-- 插入测试标签
INSERT INTO tags (tag_name)
VALUES ('科技'), ('生活'), ('搞笑');-- 插入测试内容(用户1发布图文和视频)
INSERT INTO contents (user_id, content_type, title, text_content)
VALUES
(1, 'text', '测试图文内容', '这是一段测试文本'),
(1, 'video', '测试视频内容', NULL);-- 插入多媒体文件(关联内容ID=1和2)
INSERT INTO media_files (content_id, file_type, file_url)
VALUES
(1, 'image', 'http://example.com/image1.jpg'),
(2, 'video', 'http://example.com/video1.mp4');-- 插入内容-标签关联(内容1关联科技和生活标签)
INSERT INTO content_tags (content_id, tag_id)
VALUES
(1, 1), (1, 2);
二、用户表测试(users)
1. 新增用户
-- ----------------------------
-- 二、用户表测试(users)
-- ----------------------------# 1. 新增用户
-- 正常新增(唯一邮箱/合法格式)
INSERT INTO users (username, email, password_hash)
VALUES ('test_user3', 'user3@example.com', SHA2('password3', 256));-- 异常测试:重复用户名
INSERT INTO users (username, email, password_hash)
VALUES ('test_user1', 'user4@example.com', SHA2('password4', 256)); -- 应报错(UNIQUE约束)-- 异常测试:非法邮箱格式
INSERT INTO users (username, email, password_hash)
VALUES ('test_user4', 'invalid-email', SHA2('password4', 256)); -- 应报错(CHECK约束)
2. 更新用户信息
# 2. 更新用户信息
-- 修改头像和简介
UPDATE users
SET avatar_url='http://example.com/new_avatar.jpg', bio='新简介'
WHERE user_id=1;-- 验证更新结果
SELECT username, avatar_url, bio FROM users WHERE user_id=1;
3. 删除用户
# 3. 删除用户
-- 删除用户(级联影响:内容、评论、互动、关注关系等)
DELETE FROM users WHERE user_id=3;-- 验证关联数据是否被级联删除(如contents中user_id=3的记录应被删除)
SELECT * FROM contents WHERE user_id=3; -- 应无结果
三、内容表测试(contents)
1. 发布内容
-- ----------------------------
-- 三、内容表测试(contents)
-- ----------------------------
# 1. 发布内容
-- 发布短视频(无文本内容)
INSERT INTO contents (user_id, content_type, title)
VALUES (2, 'video', '测试短视频');-- 验证内容类型和字段完整性
SELECT content_type, text_content FROM contents WHERE content_id=3; -- 应显示video和NULL
2. 更新内容
# 2. 更新内容
-- 修改标题和浏览数
UPDATE contents
SET title='更新后的标题', view_count=200
WHERE content_id=1;-- 验证更新时间是否自动更新(updated_at字段)
SELECT title, view_count, updated_at, now() FROM contents WHERE content_id=1;
3. 删除内容(级联验证)
# 3. 删除内容(级联验证)
SELECT * FROM media_files WHERE content_id=1;
-- ----------------------------
SELECT * FROM content_tags WHERE content_id=1;
-- 删除内容ID=1
DELETE FROM contents WHERE content_id=1;-- 验证关联数据是否被级联删除:
-- 1. media_files中content_id=1的记录应被删除
SELECT * FROM media_files WHERE content_id=1; -- 应无结果
-- 2. content_tags中content_id=1的记录应被删除
SELECT * FROM content_tags WHERE content_id=1; -- 应无结果
四、评论系统测试(comments)
1. 发表评论
-- ----------------------------
-- 四、评论系统测试(comments)
-- ----------------------------
# 1. 发表评论
-- 发表一级评论(父评论ID为空)
INSERT INTO comments (content_id, user_id, comment_text)
VALUES (2, 2, '这是一条评论');-- 发表回复评论(父评论ID=1)
INSERT INTO comments (content_id, user_id, parent_comment_id, comment_text)
VALUES (2, 1, 1, '这是一条回复');-- 验证评论数是否自动增加(触发器生效)
SELECT comment_count FROM contents WHERE content_id=2; -- 应显示2
2. 逻辑删除评论
# 2. 逻辑删除评论
-- 将评论ID=1标记为删除(is_deleted=true)
UPDATE comments
SET is_deleted=TRUE
WHERE comment_id=1;-- 验证评论数是否减少(触发器trg_contents_after_comment_logical_delete生效)
SELECT comment_count FROM contents WHERE content_id=2; -- 应显示1(原2条,逻辑删除1条)
3. 物理删除评论
# 3. 物理删除评论
-- 删除评论ID=2
DELETE FROM comments WHERE comment_id=2;-- 验证评论数是否进一步减少
SELECT comment_count FROM contents WHERE content_id=2; -- 应显示0
五、互动系统测试(interactions)
1. 点赞内容
-- ----------------------------
-- 五、互动系统测试(interactions)
-- ----------------------------
# 1. 点赞内容
-- 用户2点赞内容ID=2
INSERT INTO interactions (user_id, content_id, interaction_type)
VALUES (2, 2, 'like');-- 验证点赞数是否增加(触发器生效)
SELECT like_count FROM contents WHERE content_id=2; -- 应显示1
2. 取消点赞(删除互动记录)
# 2. 取消点赞(删除互动记录)
-- 删除用户2对内容ID=2的点赞记录
DELETE FROM interactions
WHERE user_id=2 AND content_id=2 AND interaction_type='like';-- 验证点赞数是否减少
SELECT like_count FROM contents WHERE content_id=2; -- 应显示0
3. 收藏内容(唯一性约束测试)
# 3. 收藏内容(唯一性约束测试)
-- 用户1收藏内容ID=2(正常插入)
INSERT INTO interactions (user_id, content_id, interaction_type)
VALUES (1, 2, 'collect');-- 重复收藏(应报错,唯一性约束)
INSERT INTO interactions (user_id, content_id, interaction_type)
VALUES (1, 2, 'collect'); -- 应失败
六、关注系统测试(follows)
1. 关注用户
-- ----------------------------
-- 六、关注系统测试(follows)
-- ----------------------------
# 1. 关注用户
-- 用户1关注用户2
INSERT INTO follows (follower_id, followed_id)
VALUES (1, 2);-- 验证关注关系是否存在
SELECT * FROM follows WHERE follower_id=1 AND followed_id=2; -- 应返回记录
2. 取消关注
# 2. 取消关注
-- 用户1取消关注用户2
DELETE FROM follows WHERE follower_id=1 AND followed_id=2;-- 验证关注关系是否删除
SELECT * FROM follows WHERE follower_id=1 AND followed_id=2; -- 应无结果
3. 统计粉丝数和关注数(通过存储过程)
# 3. 统计粉丝数和关注数(通过存储过程)
-- 调用get_user_info存储过程
CALL get_user_info('test_user1'); -- 结果应包含follower_count(0)和following_count(0)
七、标签系统测试(tags & content_tags)
1. 新增标签
-- ----------------------------
-- 七、标签系统测试(tags & content_tags)
-- ----------------------------
# 1. 新增标签
-- 新增标签“旅行”
INSERT INTO tags (tag_name)
VALUES ('旅行');-- 验证唯一性(重复插入应报错)
INSERT INTO tags (tag_name) VALUES ('旅行'); -- 应失败
2. 关联内容和标签
# 2. 关联内容和标签
-- 为内容ID=2添加“旅行”标签(tag_id=4)
INSERT INTO content_tags (content_id, tag_id)
VALUES (2, 4);-- 查询内容ID=2的标签
SELECT t.tag_name FROM tags t
JOIN content_tags ct ON t.tag_id=ct.tag_id
WHERE ct.content_id=2; -- 应返回“旅行”
3. 删除标签(级联删除关联关系)
# 3. 删除标签(级联删除关联关系)
-- 删除标签“旅行”(tag_id=4)
DELETE FROM tags WHERE tag_id=4;-- 验证content_tags中关联记录是否删除
SELECT * FROM content_tags WHERE tag_id=4; -- 应无结果
八、存储过程与函数测试
-- ----------------------------
-- 八、存储过程与函数测试
-- ----------------------------
# 1. 函数测试
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章', '这是一篇测试文章。');
select * from users where username='test_user1';
select * from contents where user_id=(select user_id from users where username='test_user1');
-- 测试user_content_count函数(用户1应有2条内容)
SELECT user_content_count('test_user1'); -- 应返回2-- 测试content_heat函数
SELECT content_heat(2); -- 应返回1
# 2. 存储过程测试(分页查询带标签的内容)
-- 插入测试数据(内容ID=2关联标签“科技”)
INSERT INTO content_tags (content_id, tag_id) VALUES (2, 1);-- 调用get_paginated_contents存储过程,查询标签为“科技”的内容
CALL get_paginated_contents('科技', NULL, NULL,1, 10, NULL, @total_count);
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章2生活', '这是一篇测试文章2。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章3生活', '这是一篇测试文章3。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章4生活', '这是一篇测试文章4。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章5生活', '这是一篇测试文章5。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章6生活', '这是一篇测试文章6。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章7生活', '这是一篇测试文章7。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章8生活', '这是一篇测试文章8。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章9生活', '这是一篇测试文章9。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章10生活', '这是一篇测试文章10。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章11', '这是一篇生活测试文章11。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章12', '这是一篇生活测试文章12。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章13', '这是一篇生活测试文章13。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '测试文章14', '这是一篇生活测试文章14。');-- 调用get_paginated_contents存储过程,查询带关键字的内容
CALL get_paginated_contents(NULL, NULL, '生活',1, 10, NULL, @total_count);
-- ----------------------------
SELECT @total_count; -- 应返回13
-- 调用get_paginated_contents存储过程,其他测试
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '快乐', '这是快乐一篇生活测试文章15。');
insert into contents (user_id, content_type, title, text_content) values (1, 'text', '快乐', '豆包,混元,………………。');CALL get_paginated_contents(NULL, NULL, '快乐',1, 10, NULL, @total_count);
-- ----------------------------
CALL get_paginated_contents(NULL, NULL, '豆包',1, 10, NULL, @total_count);
-- ----------------------------
CALL get_paginated_contents(NULL, 'video', NULL,1, 10, NULL, @total_count);
# 调用get_user_info
CALL get_user_info('test_user1');CALL get_user_info('test_user2');
九、触发器完整性验证
1. 验证互动触发器
-- ----------------------------
-- 九、触发器完整性验证
-- ----------------------------
# 1. 验证互动触发器
-- 插入点赞记录,触发like_count+1
INSERT INTO interactions (user_id, content_id, interaction_type) VALUES (1, 2, 'like');
SELECT like_count FROM contents WHERE content_id=2; -- 应显示1-- 删除点赞记录,触发like_count-1
DELETE FROM interactions WHERE content_id=2 AND interaction_type='like';
SELECT like_count FROM contents WHERE content_id=2; -- 应显示0
2. 验证评论逻辑删除触发器
# 2. 验证评论逻辑删除触发器
-- 重新插入评论并逻辑删除
INSERT INTO comments (content_id, user_id, comment_text) VALUES (2, 1, '测试评论');
UPDATE comments SET is_deleted=TRUE WHERE comment_id=3;
SELECT comment_count FROM contents WHERE content_id=2; -- 应显示0(逻辑删除后计数减少)
十、异常场景测试
1. 外键约束失败
-- ------------------
-- 十、异常场景测试
-- ------------------
# 1. 外键约束失败
-- 插入内容时指定不存在的user_id=99
INSERT INTO contents (user_id, content_type, title) VALUES (99, 'text', '非法用户'); -- 应报错(外键约束)# 2. 唯一性约束冲突
-- 插入重复的邮箱
INSERT INTO users (username, email, password_hash) VALUES ('test_user4', 'user1@example.com', SHA2('pwd', 256)); -- 应报错(email唯一)
测试点 2:数据表的并发操作
'''
# 数据库并发压力测试系统## 项目概述
本系统是针对内容社区型数据库设计的并发压力测试工具,可模拟高并发场景下的用户行为,验证数据库的事务处理能力、数据一致性和性能表现。系统基于Python开发,支持12种典型社交场景的并发测试。## 功能特性
- 支持8种核心社交操作测试
- 模拟20-50并发线程压力
- 提供自动化数据一致性验证
- 支持MySQL事务隔离级别测试
- 包含异常场景测试(级联删除、外键约束等)## 技术栈
- 语言: Python 3.12.7
- 数据库: MySQL 8.0.31
- 并发库: `concurrent.futures`
- ORM: `PyMySQL`
- 日志: `logging`模块## 测试场景
| 测试用例名称 | 并发操作数 | 验证要点 |
|----------------------------|----------|----------------------------|
| `t_concurrent_nested_comments` | 50+20 | 嵌套评论创建/删除的父子关系一致性 |
| `t_concurrent_hot_content` | 500 | 热点内容的高强度混合操作处理能力 |
| `t_concurrent_user_deletion` | 10+20 | 用户级联删除与关联数据原子性 |
| `t_concurrent_tag_creation` | 20 | 唯一约束下的标签创建冲突处理 |## 使用说明
1. 数据库配置
```python
# 修改DB_CONFIG配置
DB_CONFIG = {'host': 'localhost', # 数据库地址'user': 'root', # 数据库账号'password': '1234', # 数据库密码'database': 'contentcommunity' # 测试数据库名称
}
'''import sys
import threading
import time
import random
import pymysql
from pymysql import cursors
import logging
from concurrent.futures import ThreadPoolExecutor
import hashlib# 在文件开头修改日志配置
logging.basicConfig(level=logging.DEBUG, # 改为DEBUG级别format='%(asctime)s - %(threadName)s - %(levelname)s - %(message)s',handlers=[logging.StreamHandler()]
)
logger = logging.getLogger(__name__)# 数据库配置
DB_CONFIG = {'host': 'localhost','user': 'root','password': '1234','database': 'contentcommunity','charset': 'utf8mb4','cursorclass': cursors.DictCursor,'autocommit': False
}# 测试配置
t_CONFIG = {'num_threads': 20,'t_duration': 300,'user_prefix': 'testuser_'
}class Colors:GREEN = '\033[92m'RED = '\033[91m'YELLOW = '\033[93m'BLUE = '\033[94m'END = '\033[0m'BOLD = '\033[1m'def get_connection():"""获取数据库连接"""return pymysql.connect(**DB_CONFIG)def setup_t_data():"""初始化测试数据"""conn = get_connection()try:with conn.cursor() as cursor:# 创建测试用户for i in range(10):username = f"{t_CONFIG['user_prefix']}{i}"email = f"{username}@test.com"password_hash = hashlib.sha256(f"password{i}".encode()).hexdigest()cursor.execute("""INSERT IGNORE INTO users (username, email, password_hash, avatar_url)VALUES (%s, %s, %s, 'default_avatar.jpg')""", (username, email, password_hash))# 创建测试标签tags = ['科技', '美食', '旅行', '编程', '摄影']for tag in tags:cursor.execute("INSERT IGNORE INTO tags (tag_name) VALUES (%s)", (tag,))conn.commit()finally:conn.close()def get_random_user():"""获取随机用户"""conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT user_id FROM users ORDER BY RAND() LIMIT 1")return cursor.fetchone()['user_id']finally:conn.close()def create_t_content(user_id):"""创建测试内容"""conn = get_connection()try:with conn.cursor() as cursor:content_type = random.choice(['text', 'image', 'video'])cursor.execute("""INSERT INTO contents (user_id, content_type, title, text_content)VALUES (%s, %s, %s, %s)""", (user_id, content_type, f"测试标题_{time.time()}", "测试内容"))content_id = cursor.lastrowidif content_type != 'text':cursor.execute("""INSERT INTO media_files (content_id, file_type, file_url)VALUES (%s, %s, %s)""", (content_id, content_type, f"https://example.com/{content_id}"))conn.commit()return content_idexcept Exception as e:conn.rollback()raise efinally:conn.close()def create_comment(content_id, user_id):"""创建评论并返回评论ID"""conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("""INSERT INTO comments (content_id, user_id, comment_text)VALUES (%s, %s, '父评论')""", (content_id, user_id))conn.commit()return cursor.lastrowidexcept pymysql.Error as e:conn.rollback()raise efinally:conn.close()def t_concurrent_nested_comments():"""测试嵌套评论的并发创建"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始嵌套评论测试,内容ID:{content_id}{Colors.END}")# 先创建父评论parent_comment_id = create_comment(content_id, get_random_user())def nested_comment_task():conn = get_connection()try:user_id = get_random_user()with conn.cursor() as cursor:cursor.execute("""INSERT INTO comments (content_id, user_id, parent_comment_id, comment_text)VALUES (%s, %s, %s, '子评论')""", (content_id, user_id, parent_comment_id))conn.commit()except pymysql.IntegrityError as e:# 处理父评论可能被删除的情况if e.args[0] == 1452: # 外键约束错误conn.rollback()logger.debug(f"父评论已被删除,跳过子评论创建")else:raisefinally:conn.close()# 执行并发测试(包含可能的父评论删除操作)with ThreadPoolExecutor(max_workers=20) as executor:# 创建子评论任务comment_futures = [executor.submit(nested_comment_task) for _ in range(50)]# 添加随机删除父评论的任务def delete_parent_task():conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("""DELETE FROM comments WHERE comment_id = %s""", (parent_comment_id,))conn.commit()finally:conn.close()# 随机提交删除任务if random.random() < 0.3: # 30%概率触发删除executor.submit(delete_parent_task)# 验证结果conn = get_connection()try:with conn.cursor() as cursor:# 检查父评论是否存在cursor.execute("SELECT 1 FROM comments WHERE comment_id = %s", (parent_comment_id,))parent_exists = cursor.fetchone() is not None# 获取实际评论数cursor.execute("""SELECT COUNT(*) as total,COUNT(parent_comment_id) as child_countFROM comments WHERE content_id = %s""", (content_id,))counts = cursor.fetchone()# 验证计数器一致性cursor.execute("SELECT comment_count FROM contents WHERE content_id = %s", (content_id,))db_count = cursor.fetchone()['comment_count']# 计算预期值expected_total = counts['child_count'] + (1 if parent_exists else 0)valid = (db_count == expected_total andcounts['total'] == expected_total)return validfinally:conn.close()def t_concurrent_likes():"""测试并发点赞操作"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始点赞测试,内容ID:{content_id}{Colors.END}")def like_task():conn = get_connection()try:user_id = get_random_user()with conn.cursor() as cursor:# 检查是否已点赞cursor.execute("""SELECT 1 FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'like'""", (user_id, content_id))if cursor.fetchone():cursor.execute("""DELETE FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'like'""", (user_id, content_id))else:cursor.execute("""INSERT INTO interactions (user_id, content_id, interaction_type)VALUES (%s, %s, 'like')""", (user_id, content_id))conn.commit()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(like_task) for _ in range(100)]# 验证结果conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT like_count FROM contents WHERE content_id = %s", (content_id,))actual_likes = cursor.fetchone()['like_count']cursor.execute("SELECT COUNT(*) FROM interactions WHERE content_id = %s", (content_id,))interaction_count = cursor.fetchone()['COUNT(*)']return actual_likes == interaction_countfinally:conn.close()def t_concurrent_comments():"""测试并发评论操作"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始评论测试,内容ID:{content_id}{Colors.END}")def comment_task():conn = get_connection()try:user_id = get_random_user()with conn.cursor() as cursor:cursor.execute("""INSERT INTO comments (content_id, user_id, comment_text)VALUES (%s, %s, %s)""", (content_id, user_id, "测试评论"))conn.commit()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(comment_task) for _ in range(50)]# 验证结果conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT comment_count FROM contents WHERE content_id = %s", (content_id,))actual_comments = cursor.fetchone()['comment_count']cursor.execute("SELECT COUNT(*) FROM comments WHERE content_id = %s", (content_id,))comment_count = cursor.fetchone()['COUNT(*)']return actual_comments == comment_countfinally:conn.close()def t_concurrent_follows():"""测试并发关注操作"""user1 = get_random_user()user2 = get_random_user()logger.info(f"{Colors.BLUE}▶ 开始关注测试,用户:{user1} -> {user2}{Colors.END}")def follow_task():conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("""SELECT 1 FROM follows WHERE follower_id = %s AND followed_id = %s""", (user1, user2))if cursor.fetchone():cursor.execute("""DELETE FROM follows WHERE follower_id = %s AND followed_id = %s""", (user1, user2))else:cursor.execute("""INSERT INTO follows (follower_id, followed_id)VALUES (%s, %s)""", (user1, user2))conn.commit()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(follow_task) for _ in range(50)]# 验证结果conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT COUNT(*) FROM follows WHERE follower_id = %s AND followed_id = %s", (user1, user2))actual_follows = cursor.fetchone()['COUNT(*)']return actual_follows in (0, 1)finally:conn.close()def t_concurrent_content_creation():"""测试并发内容创建"""logger.info(f"{Colors.BLUE}▶ 开始内容创建测试{Colors.END}")results = []def create_task():try:user_id = get_random_user()content_id = create_t_content(user_id)return content_id is not Noneexcept Exception as e:return False# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(create_task) for _ in range(50)]results = [f.result() for f in futures]return all(results)def t_concurrent_tagging():"""测试并发标签关联"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始标签测试,内容ID:{content_id}{Colors.END}")def tag_task():conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT tag_id FROM tags ORDER BY RAND() LIMIT 1")tag_id = cursor.fetchone()['tag_id']cursor.execute("""INSERT IGNORE INTO content_tags (content_id, tag_id)VALUES (%s, %s)""", (content_id, tag_id))conn.commit()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(tag_task) for _ in range(20)]# 验证结果conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT COUNT(DISTINCT tag_id) FROM content_tags WHERE content_id = %s", (content_id,))unique_tags = cursor.fetchone()['COUNT(DISTINCT tag_id)']return unique_tags > 0finally:conn.close()def t_concurrent_updates():"""测试并发更新操作"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始更新测试,内容ID:{content_id}{Colors.END}")def update_task():conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("""UPDATE contents SET view_count = view_count + 1 WHERE content_id = %s""", (content_id,))conn.commit()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(update_task) for _ in range(100)]# 验证结果conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT view_count FROM contents WHERE content_id = %s", (content_id,))view_count = cursor.fetchone()['view_count']return view_count == 100finally:conn.close()def t_concurrent_collects():"""测试并发收藏操作"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始收藏测试,内容ID:{content_id}{Colors.END}")def collect_task():conn = get_connection()try:user_id = get_random_user()with conn.cursor() as cursor:cursor.execute("""SELECT 1 FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'collect'""", (user_id, content_id))if cursor.fetchone():cursor.execute("""DELETE FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'collect'""", (user_id, content_id))else:cursor.execute("""INSERT INTO interactions (user_id, content_id, interaction_type)VALUES (%s, %s, 'collect')""", (user_id, content_id))conn.commit()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(collect_task) for _ in range(100)]# 验证结果conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT collect_count FROM contents WHERE content_id = %s", (content_id,))actual_collects = cursor.fetchone()['collect_count']cursor.execute("SELECT COUNT(*) FROM interactions WHERE content_id = %s", (content_id,))interaction_count = cursor.fetchone()['COUNT(*)']return actual_collects == interaction_countfinally:conn.close()# 在原有代码基础上新增以下测试函数
def t_concurrent_user_updates():"""测试并发用户资料更新"""user_id = get_random_user()logger.info(f"{Colors.BLUE}▶ 开始用户资料更新测试,用户ID:{user_id}{Colors.END}")def update_task():conn = get_connection()try:with conn.cursor() as cursor:# 模拟更新头像和简介new_avatar = f"avatar_{random.randint(1,100)}.jpg"new_bio = f"Bio updated at {time.time()}"cursor.execute("""UPDATE users SET avatar_url = %s, bio = %s WHERE user_id = %s""", (new_avatar, new_bio, user_id))conn.commit()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(update_task) for _ in range(50)]# 验证最终一致性conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT avatar_url, bio FROM users WHERE user_id = %s", (user_id,))result = cursor.fetchone()return result['avatar_url'].startswith('avatar_') and len(result['bio']) > 0finally:conn.close()def t_concurrent_content_deletion():"""测试并发内容删除(测试级联删除触发器)"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始内容删除测试,内容ID:{content_id}{Colors.END}")def delete_task():conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("DELETE FROM contents WHERE content_id = %s", (content_id,))conn.commit()except pymysql.IntegrityError as e:conn.rollback()finally:conn.close()# 并发删除和创建相关数据with ThreadPoolExecutor(max_workers=20) as executor:# 启动删除线程delete_futures = [executor.submit(delete_task) for _ in range(10)]# 同时创建相关数据测试并发冲突def create_related_data():conn = get_connection()try:user_id = get_random_user()# 测试创建评论conn.cursor().execute("""INSERT INTO comments (content_id, user_id, comment_text)VALUES (%s, %s, '测试评论')""", (content_id, user_id))# 测试添加标签conn.cursor().execute("""INSERT INTO content_tags (content_id, tag_id)SELECT %s, tag_id FROM tags ORDER BY RAND() LIMIT 1""", (content_id,))conn.commit()except pymysql.Error:conn.rollback()finally:conn.close()data_futures = [executor.submit(create_related_data) for _ in range(20)]# 验证最终删除结果conn = get_connection()try:with conn.cursor() as cursor:# 检查内容是否存在cursor.execute("SELECT 1 FROM contents WHERE content_id = %s", (content_id,))content_exists = cursor.fetchone() is not None# 检查关联数据cursor.execute("SELECT 1 FROM comments WHERE content_id = %s", (content_id,))comments_exist = cursor.fetchone() is not Nonecursor.execute("SELECT 1 FROM content_tags WHERE content_id = %s", (content_id,))tags_exist = cursor.fetchone() is not Nonereturn not (content_exists or comments_exist or tags_exist)finally:conn.close()def t_concurrent_tag_creation():"""测试并发标签创建(测试唯一约束)"""tag_name = f"t_tag_{int(time.time())}"logger.info(f"{Colors.BLUE}▶ 开始标签创建测试,标签名:{tag_name}{Colors.END}")def create_tag_task():conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("""INSERT INTO tags (tag_name) VALUES (%s)""", (tag_name,))conn.commit()except pymysql.IntegrityError:conn.rollback()finally:conn.close()# 执行并发测试with ThreadPoolExecutor(max_workers=20) as executor:futures = [executor.submit(create_tag_task) for _ in range(20)]# 验证结果conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("SELECT COUNT(*) FROM tags WHERE tag_name = %s", (tag_name,))count = cursor.fetchone()['COUNT(*)']return count == 1finally:conn.close()def t_concurrent_user_deletion():"""测试并发用户删除(测试外键约束和级联删除)"""user_id = get_random_user()content_id = create_t_content(user_id)logger.info(f"{Colors.BLUE}▶ 开始用户删除测试,用户ID:{user_id}{Colors.END}")def delete_task():conn = get_connection()try:with conn.cursor() as cursor:cursor.execute("DELETE FROM users WHERE user_id = %s", (user_id,))conn.commit()except pymysql.Error:conn.rollback()finally:conn.close()def create_data_task():conn = get_connection()try:# 尝试创建关联数据with conn.cursor() as cursor:# 创建关注关系cursor.execute("""INSERT INTO follows (follower_id, followed_id)VALUES (%s, %s)""", (user_id, get_random_user()))# 创建互动cursor.execute("""INSERT INTO interactions (user_id, content_id, interaction_type)VALUES (%s, %s, 'like')""", (user_id, content_id))conn.commit()except pymysql.Error:conn.rollback()finally:conn.close()# 并发删除和创建关联数据with ThreadPoolExecutor(max_workers=20) as executor:del_futures = [executor.submit(delete_task) for _ in range(10)]data_futures = [executor.submit(create_data_task) for _ in range(20)]# 验证删除结果conn = get_connection()try:with conn.cursor() as cursor:# 检查用户是否存在cursor.execute("SELECT 1 FROM users WHERE user_id = %s", (user_id,))user_exists = cursor.fetchone() is not None# 检查关联数据cursor.execute("SELECT 1 FROM contents WHERE user_id = %s", (user_id,))content_exists = cursor.fetchone() is not Nonecursor.execute("SELECT 1 FROM follows WHERE follower_id = %s", (user_id,))follows_exist = cursor.fetchone() is not Nonereturn not (user_exists or content_exists or follows_exist)finally:conn.close()def t_concurrent_hot_content():"""测试热门内容的极端并发"""content_id = create_t_content(get_random_user())logger.info(f"{Colors.BLUE}▶ 开始热门内容测试,内容ID:{content_id}{Colors.END}")def hot_content_task():conn = get_connection()try:with conn.cursor() as cursor:# 随机选择操作类型operation = random.choice(['like', 'unlike','comment','collect', 'uncollect'])user_id = get_random_user()if operation in ['like', 'collect']:# 插入互动cursor.execute("""INSERT IGNORE INTO interactions (user_id, content_id, interaction_type)VALUES (%s, %s, %s)""", (user_id, content_id, operation))elif operation in ['unlike', 'uncollect']:# 删除互动cursor.execute("""DELETE FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = %s""", (user_id, content_id, operation.replace('un','')))elif operation == 'comment':# 创建评论cursor.execute("""INSERT INTO comments (content_id, user_id, comment_text)VALUES (%s, %s, '热门内容评论')""", (content_id, user_id))conn.commit()finally:conn.close()# 执行高强度并发with ThreadPoolExecutor(max_workers=50) as executor:futures = [executor.submit(hot_content_task) for _ in range(500)]# 验证最终一致性conn = get_connection()try:with conn.cursor() as cursor:# 获取内容统计cursor.execute("""SELECT like_count, collect_count,comment_count FROM contents WHERE content_id = %s""", (content_id,))content_stats = cursor.fetchone()# 获取实际互动数据cursor.execute("""SELECT SUM(IF(interaction_type='like',1,0)) as actual_likes,SUM(IF(interaction_type='collect',1,0)) as actual_collects,(SELECT COUNT(*) FROM comments WHERE content_id=%s) as actual_commentsFROM interactions WHERE content_id=%s""", (content_id, content_id))actual_stats = cursor.fetchone()# 验证计数器一致性return (content_stats['like_count'] == actual_stats['actual_likes'] andcontent_stats['collect_count'] == actual_stats['actual_collects'] andcontent_stats['comment_count'] == actual_stats['actual_comments'])finally:conn.close()def run_tests():"""运行所有测试用例"""tests = [t_concurrent_likes,t_concurrent_collects,t_concurrent_comments,t_concurrent_follows,t_concurrent_content_creation,t_concurrent_tagging,t_concurrent_updates,t_concurrent_user_updates, # 新增t_concurrent_content_deletion, # 新增t_concurrent_nested_comments, # 新增 t_concurrent_tag_creation, # 新增t_concurrent_user_deletion, # 新增t_concurrent_hot_content # 新增]passed = 0failed = 0results = []logger.info(f"\n{Colors.BOLD}{Colors.BLUE}=== 开始并发测试 ({len(tests)} 个测试用例) ==={Colors.END}\n")for test in tests:try:start = time.time()result = test()duration = time.time() - startif result:status = f"{Colors.GREEN}✓ 通过{Colors.END}"passed += 1else:status = f"{Colors.RED}✗ 失败{Colors.END}"failed += 1logger.info(f"{Colors.BOLD}{test.__name__}: {status}")logger.info(f"耗时: {duration:.2f}s{Colors.END}")results.append((test.__name__, result, duration))except Exception as e:logger.error(f"{Colors.RED}测试异常: {str(e)}{Colors.END}")failed += 1results.append((test.__name__, False, 0))# 打印总结报告logger.info(f"\n{Colors.BOLD}{Colors.BLUE}=== 测试总结 ==={Colors.END}")logger.info(f"总用例数: {len(tests)}")logger.info(f"{Colors.GREEN}通过用例: {passed}{Colors.END}")logger.info(f"{Colors.RED}失败用例: {failed}{Colors.END}")logger.info(f"通过率: {(passed/len(tests))*100:.1f}%")return passed == len(tests)if __name__ == "__main__":try:# 初始化测试数据setup_t_data()# 运行测试套件success = run_tests()# 返回适当的退出码sys.exit(0 if success else 1)except Exception as e:logger.error(f"{Colors.RED}测试执行失败: {str(e)}{Colors.END}")sys.exit(1)
测试点 3:边界条件测试(表满 / 空状态)
测试执行说明:
1. 完整性和隔离性:每个测试用例使用独立事务,确保测试环境隔离
2. 异常处理:通过IF EXISTS子句处理可能不存在的对象
3. 结果验证:
- 使用ROW_COUNT()验证影响行数
- 检查外键约束是否阻止非法操作
- 验证触发器在空表场景下的稳定性
4. 覆盖范围:
- 所有用户提供的表结构
- 级联删除约束
- 触发器空触发场景
- 基础DDL/DML操作边界情况
-- 数据库删除与清空测试套件
-- 测试用例设计说明:
-- 1. 测试所有表的空表删除操作
-- 2. 测试空表记录删除操作
-- 3. 验证外键约束与触发器在空表场景下的表现-- -----------------------------------
-- 测试用例1:数据库级删除测试
-- -----------------------------------
-- 场景:空数据库删除验证
DROP DATABASE IF EXISTS contentcommunity;
SELECT '空数据库删除测试完成' AS test_result;
-- -----------------------------------
-- 测试用例2:表级删除测试
-- -----------------------------------
-- 初始化环境
CREATE DATABASE IF NOT EXISTS contentcommunity;
-- -----------------------
-- 重建表结构(保持空表状态)
-- 这里需要执行完整建表SQL
# 运行MySQL脚本【此处省略…………】
-- -----------------------
USE contentcommunity;-- 场景:空表删除操作验证
-- 注意按照依赖关系逆序删除
DROP TABLE IF EXISTS follows;
DROP TABLE IF EXISTS interactions;
DROP TABLE IF EXISTS comments;
DROP TABLE IF EXISTS content_tags;
DROP TABLE IF EXISTS tags;
DROP TABLE IF EXISTS media_files;
DROP TABLE IF EXISTS contents;
DROP TABLE IF EXISTS users;
SELECT '空表删除操作验证完成' AS test_result;
-- -----------------------------------
-- 测试用例3:空表记录删除测试
-- -----------------------------------
-- 重建表结构(保持空表状态)
-- 这里需要执行完整建表SQL
# 运行MySQL脚本【此处省略…………】-- 场景:验证空表数据删除操作
START TRANSACTION;
-- 测试数据删除语句
DELETE FROM follows;
DELETE FROM interactions;
DELETE FROM comments;
DELETE FROM content_tags;
DELETE FROM tags;
DELETE FROM media_files;
DELETE FROM contents;
DELETE FROM users;
-- 验证影响行数
SELECT ROW_COUNT() AS affected_rows;
COMMIT;
-- -------------------------------------
SELECT '空表记录删除操作验证完成' AS test_result;
-- -----------------------------------
-- 测试用例4:空表约束验证
-- -----------------------------------
-- 重建表结构(保持空表状态)
-- 这里需要执行完整建表SQL
# 运行MySQL脚本【此处省略…………】-- 验证外键约束在空表场景下的表现
-- 必须按照实际表结构提供完整字段值
INSERT INTO users (username,email,password_hash
) VALUES ('test_user','test@example.com','a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3' -- 123的SHA256哈希
);-- 验证级联删除(需补充关联表结构)
-- 创建关联内容测试数据
INSERT INTO contents (user_id,content_type,title
) VALUES ((SELECT user_id FROM users WHERE username = 'test_user'),'text','测试内容'
);-- 执行级联删除验证
DELETE FROM users WHERE username = 'test_user';-- 验证关联内容是否被级联删除
SELECT COUNT(*) AS remaining_contents
FROM contents
WHERE user_id = (SELECT user_id FROM users WHERE username = 'test_user');-- -----------------------------------------
SELECT '空表约束验证完成' AS test_result;
-- -----------------------------------------
-- 测试用例5:触发器空表测试
-- -----------------------------------------
-- 验证空表触发器的稳定性
-- 创建测试触发器(示例)
DELIMITER $$
CREATE TRIGGER trg_test
BEFORE DELETE ON users
FOR EACH ROW
BEGINDELETE FROM contents WHERE user_id = OLD.user_id;
END$$
DELIMITER ;-- 执行空表删除操作
DELETE FROM users; -- 验证触发器不会报错
DROP TRIGGER trg_test;
SELECT '空表触发器验证完成' AS test_result;
测试点4:针对存储过程的接口测试
-
初始化设置:禁用外键检查,清空测试数据并重置自增 ID,然后启用外键检查。
-- ---------------------------- -- 内容社区系统存储过程测试脚本 -- ------------------------------ 使用内容社区数据库 USE contentcommunity;-- 禁用外键检查,以便于测试数据的插入和删除 SET FOREIGN_KEY_CHECKS = 0;-- 清空测试数据(如果存在) DELETE FROM interactions; DELETE FROM comments; DELETE FROM content_tags; DELETE FROM media_files; DELETE FROM contents; DELETE FROM tags; DELETE FROM follows; DELETE FROM users;-- 重置自增ID ALTER TABLE users AUTO_INCREMENT = 1; ALTER TABLE contents AUTO_INCREMENT = 1; ALTER TABLE media_files AUTO_INCREMENT = 1; ALTER TABLE tags AUTO_INCREMENT = 1; ALTER TABLE comments AUTO_INCREMENT = 1; ALTER TABLE interactions AUTO_INCREMENT = 1; ALTER TABLE follows AUTO_INCREMENT = 1;-- 启用外键检查 SET FOREIGN_KEY_CHECKS = 1;-- 开始测试 SELECT '开始测试存储过程' AS '测试状态';
-
测试数据准备:创建 3 个测试用户、7 个标签、5 个内容(包括文本、图片和视频)、6 条评论、13 条互动记录和 5 条关注关系。
-- ---------------------------- -- 测试数据准备 -- ---------------------------- INSERT INTO users (username, email, password_hash, avatar_url, bio, registration_date, last_login) VALUES ('test_user1', 'test1@example.com', SHA2('password1', 256), 'https://example.com/avatar1.jpg', '测试用户1', NOW() - INTERVAL 30 DAY, NOW() - INTERVAL 1 DAY), ('test_user2', 'test2@example.com', SHA2('password2', 256), 'https://example.com/avatar2.jpg', '测试用户2', NOW() - INTERVAL 20 DAY, NOW() - INTERVAL 2 DAY), ('test_user3', 'test3@example.com', SHA2('password3', 256), 'https://example.com/avatar3.jpg', '测试用户3', NOW() - INTERVAL 10 DAY, NOW() - INTERVAL 3 DAY);INSERT INTO tags (tag_name) VALUES ('技术'), ('生活'), ('美食'), ('旅行'), ('摄影'), ('编程'), ('AI');INSERT INTO contents (user_id, content_type, title, text_content, created_at, view_count, like_count, comment_count, collect_count) VALUES (1, 'text', 'Python编程技巧分享', '这是一篇关于Python编程的技巧分享文章...', NOW() - INTERVAL 5 DAY, 100, 20, 5, 10), (1, 'image', '美丽的自然风光', '', NOW() - INTERVAL 4 DAY, 150, 30, 7, 15), (2, 'video', '美食制作教程', '', NOW() - INTERVAL 3 DAY, 200, 40, 10, 20), (2, 'text', '旅行见闻', '分享我的旅行经历和见闻...', NOW() - INTERVAL 2 DAY, 80, 15, 3, 8), (3, 'image', '城市建筑摄影', '', NOW() - INTERVAL 1 DAY, 120, 25, 6, 12);INSERT INTO media_files (content_id, file_type, file_url) VALUES (2, 'image', 'https://example.com/image1.jpg'), (3, 'video', 'https://example.com/video1.mp4'), (5, 'image', 'https://example.com/image2.jpg');INSERT INTO content_tags (content_id, tag_id) VALUES (1, 1), (1, 6), (2, 4), (2, 5), (3, 3), (4, 4), (5, 5);INSERT INTO comments (content_id, user_id, parent_comment_id, comment_text, created_at, like_count) VALUES (1, 2, NULL, '非常实用的技巧!', NOW() - INTERVAL 4 DAY, 5), (1, 3, NULL, '感谢分享!', NOW() - INTERVAL 3 DAY, 3), (2, 1, NULL, '风景真美!', NOW() - INTERVAL 3 DAY, 7), (2, 3, 3, '请问这是在哪里拍摄的?', NOW() - INTERVAL 2 DAY, 2), (3, 1, NULL, '看起来很好吃!', NOW() - INTERVAL 2 DAY, 4), (3, 2, NULL, '请问用的什么食材?', NOW() - INTERVAL 1 DAY, 3);INSERT INTO interactions (user_id, content_id, interaction_type, interacted_at) VALUES (2, 1, 'like', NOW() - INTERVAL 4 DAY), (3, 1, 'like', NOW() - INTERVAL 3 DAY), (1, 2, 'like', NOW() - INTERVAL 3 DAY), (3, 2, 'like', NOW() - INTERVAL 2 DAY), (1, 3, 'like', NOW() - INTERVAL 2 DAY), (2, 3, 'like', NOW() - INTERVAL 1 DAY), (3, 4, 'like', NOW() - INTERVAL 1 DAY), (1, 5, 'like', NOW() - INTERVAL 1 DAY), (2, 5, 'like', NOW() - INTERVAL 1 DAY), (2, 1, 'collect', NOW() - INTERVAL 3 DAY), (3, 2, 'collect', NOW() - INTERVAL 2 DAY), (1, 3, 'collect', NOW() - INTERVAL 2 DAY);INSERT INTO follows (follower_id, followed_id, created_at) VALUES (2, 1, NOW() - INTERVAL 5 DAY), (3, 1, NOW() - INTERVAL 4 DAY), (1, 2, NOW() - INTERVAL 3 DAY), (3, 2, NOW() - INTERVAL 2 DAY), (1, 3, NOW() - INTERVAL 1 DAY);
-
存储过程测试:
get_paginated_contents
存储过程测试:- 无筛选条件的分页查询
-- ---------------------------- -- 测试 get_paginated_contents 存储过程 -- ---------------------------- SELECT '测试 get_paginated_contents 存储过程' AS '测试状态';-- 测试1:无筛选条件,第一页,每页2条记录 SELECT '测试1:无筛选条件,第一页,每页2条记录' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents(NULL, NULL, NULL, 1, 2, NULL, @total_count); SELECT @total_count AS '总记录数';
- 按标签、内容类型、关键词和用户名的单独筛选
-- 测试2:按标签筛选(技术) SELECT '测试2:按标签筛选(技术)' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents('技术', NULL, NULL,1, 10, NULL, @total_count); SELECT @total_count AS '总记录数';-- 测试3:按内容类型筛选(text) SELECT '测试3:按内容类型筛选(text)' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents(NULL, 'text', NULL, 1, 10, NULL, @total_count); SELECT @total_count AS '总记录数';-- 测试4:按关键词筛选(Python) SELECT '测试4:按关键词筛选(Python)' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents(NULL, NULL, 'Python', 1, 10, NULL, @total_count); SELECT @total_count AS '总记录数';-- 测试5:按用户名筛选(test_user2) SELECT '测试5:按用户名筛选(test_user2)' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents(NULL, NULL, NULL, 1, 10, 'test_user2', @total_count); SELECT @total_count AS '总记录数';
- 组合筛选
-- 测试6:组合筛选(标签+内容类型+关键词) SELECT '测试6:组合筛选(标签+内容类型+关键词)' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents('技术,编程', 'text', '技巧',1, 10, NULL, @total_count); -- --------------------------------------------------------------------------------------------- SELECT @total_count AS '总记录数';
- 不存在的筛选条件测试
-- 测试7:不存在的筛选条件 SELECT '测试7:不存在的筛选条件' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents('不存在的标签', NULL, NULL,1, 10, NULL, @total_count); -- --------------------------------------------------------------------------------------------- SELECT @total_count AS '总记录数';
- 分页功能测试
-- 测试8:分页测试,第二页,每页2条记录 SELECT '测试8:分页测试,第二页,每页2条记录' AS '测试用例'; SET @total_count = 0; CALL get_paginated_contents(NULL, NULL, NULL,2, 2, NULL, @total_count); -- --------------------------------------------------------------------------------------------- SELECT @total_count AS '总记录数';
- 无筛选条件的分页查询
get_user_info
存储过程测试:- 查询存在的用户
-- ---------------------------- -- 测试 get_user_info 存储过程 -- ---------------------------- SELECT '测试 get_user_info 存储过程' AS '测试状态';-- 测试1:查询存在的用户(test_user1) SELECT '测试1:查询存在的用户(test_user1)' AS '测试用例'; -- --------------------------------------------------------------------------------------------- CALL get_user_info('test_user1');-- 测试2:查询存在的用户(test_user2) SELECT '测试2:查询存在的用户(test_user2)' AS '测试用例'; -- --------------------------------------------------------------------------------------------- CALL get_user_info('test_user2');-- 测试3:查询存在的用户(test_user3) SELECT '测试3:查询存在的用户(test_user3)' AS '测试用例'; -- --------------------------------------------------------------------------------------------- CALL get_user_info('test_user3');
- 查询不存在的用户
-- 测试4:查询不存在的用户 SELECT '测试4:查询不存在的用户' AS '测试用例'; -- --------------------------------------------------------------------------------------------- CALL get_user_info('不存在的用户');
- 查询存在的用户
-
测试结果验证:显示测试完成信息。
-- ----------------------------
-- 测试结果验证
-- ----------------------------
SELECT '测试完成' AS '测试状态';
测试点5:结合业务逻辑做关联表的接口测试
import hashlibimport pymysql
import unittest
import random
import string# 数据库配置
DB_CONFIG = {'host': 'localhost','user': 'root','password': '1234','database': 'contentcommunity','charset': 'utf8mb4','autocommit': True
}class DatabaseTester(unittest.TestCase):@classmethoddef setUpClass(cls):cls.conn = pymysql.connect(**DB_CONFIG)cls.cursor = cls.conn.cursor(pymysql.cursors.DictCursor)print("数据库连接成功")@classmethoddef tearDownClass(cls):cls.cursor.close()cls.conn.close()print("数据库连接关闭")def setUp(self):# 测试前清理相关数据self.clean_up()print("测试环境准备完成")def tearDown(self):# 测试后清理相关数据self.clean_up()print("测试环境清理完成")def clean_up(self):# 清理顺序需考虑外键约束,从子表到父表self.cursor.execute("DELETE FROM follows")self.cursor.execute("DELETE FROM interactions")self.cursor.execute("DELETE FROM comments")self.cursor.execute("DELETE FROM content_tags")self.cursor.execute("DELETE FROM media_files")self.cursor.execute("DELETE FROM contents")self.cursor.execute("DELETE FROM tags")self.cursor.execute("DELETE FROM users WHERE username != 'admin'")def generate_random_string(self, length=10):letters = string.ascii_letters + string.digitsreturn ''.join(random.choice(letters) for _ in range(length))def test_user_registration_and_login(self):"""测试用户注册和登录功能"""# 生成随机测试用户username = "test_user_" + self.generate_random_string()email = username + "@example.com"password = "TestPassword123!"# 注册用户self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(username, email, hashlib.sha256(password.encode()).hexdigest()))# 验证注册成功self.cursor.execute("SELECT * FROM users WHERE username = %s", (username,))user = self.cursor.fetchone()self.assertIsNotNone(user)self.assertEqual(user['username'], username)self.assertEqual(user['email'], email)# 模拟登录self.cursor.execute("SELECT password_hash FROM users WHERE username = %s", (username,))result = self.cursor.fetchone()self.assertIsNotNone(result)self.assertEqual(result['password_hash'], hashlib.sha256(password.encode()).hexdigest())def test_content_creation_and_management(self):"""测试内容创建和管理功能"""# 创建测试用户test_username = "content_user_" + self.generate_random_string()test_email = test_username + "@example.com"test_password = "ContentPassword123!"self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(test_username, test_email, hashlib.sha256(test_password.encode()).hexdigest()))self.cursor.execute("SELECT user_id FROM users WHERE username = %s", (test_username,))user_id = self.cursor.fetchone()['user_id']# 创建内容title = "测试文章标题"content = "这是测试文章内容"self.cursor.execute("INSERT INTO contents (user_id, content_type, title, text_content) VALUES (%s, %s, %s, %s)",(user_id, 'text', title, content))self.cursor.execute("SELECT LAST_INSERT_ID()")content_id = self.cursor.fetchone()['LAST_INSERT_ID()']# 验证内容创建self.cursor.execute("SELECT * FROM contents WHERE content_id = %s", (content_id,))created_content = self.cursor.fetchone()self.assertIsNotNone(created_content)self.assertEqual(created_content['title'], title)self.assertEqual(created_content['text_content'], content)# 编辑内容new_title = "更新后的测试标题"new_content = "更新后的测试内容"self.cursor.execute("UPDATE contents SET title = %s, text_content = %s WHERE content_id = %s",(new_title, new_content, content_id))# 验证内容更新self.cursor.execute("SELECT * FROM contents WHERE content_id = %s", (content_id,))updated_content = self.cursor.fetchone()self.assertEqual(updated_content['title'], new_title)self.assertEqual(updated_content['text_content'], new_content)# 删除内容self.cursor.execute("DELETE FROM contents WHERE content_id = %s", (content_id,))# 验证内容删除self.cursor.execute("SELECT * FROM contents WHERE content_id = %s", (content_id,))deleted_content = self.cursor.fetchone()self.assertIsNone(deleted_content)def test_media_file_management(self):"""测试多媒体文件管理功能"""# 创建测试用户和内容test_username = "media_user_" + self.generate_random_string()test_email = test_username + "@example.com"test_password = "MediaPassword123!"self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(test_username, test_email, hashlib.sha256(test_password.encode()).hexdigest()))self.cursor.execute("SELECT user_id FROM users WHERE username = %s", (test_username,))user_id = self.cursor.fetchone()['user_id']self.cursor.execute("INSERT INTO contents (user_id, content_type, title) VALUES (%s, %s, %s)",(user_id, 'image', "测试图片内容"))self.cursor.execute("SELECT LAST_INSERT_ID()")content_id = self.cursor.fetchone()['LAST_INSERT_ID()']# 添加多媒体文件file_url = "https://example.com/test-image.jpg"self.cursor.execute("INSERT INTO media_files (content_id, file_type, file_url) VALUES (%s, %s, %s)",(content_id, 'image', file_url))# 验证文件添加self.cursor.execute("SELECT * FROM media_files WHERE content_id = %s", (content_id,))media_file = self.cursor.fetchone()self.assertIsNotNone(media_file)self.assertEqual(media_file['file_url'], file_url)# 删除多媒体文件(通过删除内容级联删除)self.cursor.execute("DELETE FROM contents WHERE content_id = %s", (content_id,))# 验证文件删除self.cursor.execute("SELECT * FROM media_files WHERE content_id = %s", (content_id,))deleted_media = self.cursor.fetchone()self.assertIsNone(deleted_media)def test_tag_management(self):"""测试标签管理功能"""# 创建测试标签tag_name1 = "测试标签1_" + self.generate_random_string()tag_name2 = "测试标签2_" + self.generate_random_string()self.cursor.execute("INSERT INTO tags (tag_name) VALUES (%s)", (tag_name1,))self.cursor.execute("INSERT INTO tags (tag_name) VALUES (%s)", (tag_name2,))# 验证标签创建self.cursor.execute("SELECT * FROM tags WHERE tag_name = %s", (tag_name1,))tag1 = self.cursor.fetchone()self.assertIsNotNone(tag1)self.cursor.execute("SELECT * FROM tags WHERE tag_name = %s", (tag_name2,))tag2 = self.cursor.fetchone()self.assertIsNotNone(tag2)# 创建测试内容并关联标签test_username = "tag_user_" + self.generate_random_string()test_email = test_username + "@example.com"test_password = "TagPassword123!"self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(test_username, test_email, hashlib.sha256(test_password.encode()).hexdigest()))self.cursor.execute("SELECT user_id FROM users WHERE username = %s", (test_username,))user_id = self.cursor.fetchone()['user_id']self.cursor.execute("INSERT INTO contents (user_id, content_type, title) VALUES (%s, %s, %s)",(user_id, 'text', "测试标签内容"))self.cursor.execute("SELECT LAST_INSERT_ID()")content_id = self.cursor.fetchone()['LAST_INSERT_ID()']self.cursor.execute("INSERT INTO content_tags (content_id, tag_id) VALUES (%s, %s)",(content_id, tag1['tag_id']))self.cursor.execute("INSERT INTO content_tags (content_id, tag_id) VALUES (%s, %s)",(content_id, tag2['tag_id']))# 验证标签关联self.cursor.execute("""SELECT t.tag_name FROM content_tags ctJOIN tags t ON ct.tag_id = t.tag_idWHERE ct.content_id = %s""", (content_id,))associated_tags = self.cursor.fetchall()self.assertEqual(len(associated_tags), 2)self.assertIn(tag_name1, [tag['tag_name'] for tag in associated_tags])self.assertIn(tag_name2, [tag['tag_name'] for tag in associated_tags])# 删除内容(级联删除标签关联)self.cursor.execute("DELETE FROM contents WHERE content_id = %s", (content_id,))# 验证标签关联删除self.cursor.execute("""SELECT * FROM content_tags WHERE content_id = %s""", (content_id,))remaining_tags = self.cursor.fetchall()self.assertEqual(len(remaining_tags), 0)def test_comment_system(self):"""测试评论系统功能"""# 创建测试用户和内容test_username = "comment_user_" + self.generate_random_string()test_email = test_username + "@example.com"test_password = "CommentPassword123!"self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(test_username, test_email, hashlib.sha256(test_password.encode()).hexdigest()))self.cursor.execute("SELECT user_id FROM users WHERE username = %s", (test_username,))user_id = self.cursor.fetchone()['user_id']self.cursor.execute("INSERT INTO contents (user_id, content_type, title) VALUES (%s, %s, %s)",(user_id, 'text', "测试评论内容"))self.cursor.execute("SELECT LAST_INSERT_ID()")content_id = self.cursor.fetchone()['LAST_INSERT_ID()']# 发布评论comment_text = "这是测试评论"self.cursor.execute("INSERT INTO comments (content_id, user_id, comment_text) VALUES (%s, %s, %s)",(content_id, user_id, comment_text))self.cursor.execute("SELECT LAST_INSERT_ID()")comment_id = self.cursor.fetchone()['LAST_INSERT_ID()']# 验证评论发布self.cursor.execute("SELECT * FROM comments WHERE comment_id = %s", (comment_id,))posted_comment = self.cursor.fetchone()self.assertIsNotNone(posted_comment)self.assertEqual(posted_comment['comment_text'], comment_text)# 发布子评论reply_text = "这是子评论"self.cursor.execute("INSERT INTO comments (content_id, user_id, comment_text, parent_comment_id) VALUES (%s, %s, %s, %s)",(content_id, user_id, reply_text, comment_id))self.cursor.execute("SELECT LAST_INSERT_ID()")reply_id = self.cursor.fetchone()['LAST_INSERT_ID()']# 验证子评论发布self.cursor.execute("SELECT * FROM comments WHERE comment_id = %s", (reply_id,))posted_reply = self.cursor.fetchone()self.assertIsNotNone(posted_reply)self.assertEqual(posted_reply['comment_text'], reply_text)self.assertEqual(posted_reply['parent_comment_id'], comment_id)# 删除主评论(级联删除子评论)self.cursor.execute("DELETE FROM comments WHERE comment_id = %s", (comment_id,))# 验证评论删除self.cursor.execute("SELECT * FROM comments WHERE comment_id = %s", (comment_id,))deleted_comment = self.cursor.fetchone()self.assertIsNone(deleted_comment)self.cursor.execute("SELECT * FROM comments WHERE comment_id = %s", (reply_id,))deleted_reply = self.cursor.fetchone()self.assertIsNone(deleted_reply)def test_interaction_system(self):"""测试用户互动系统功能"""# 创建测试用户和内容test_username = "interaction_user_" + self.generate_random_string()test_email = test_username + "@example.com"test_password = "InteractionPassword123!"self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(test_username, test_email, hashlib.sha256(test_password.encode()).hexdigest()))self.cursor.execute("SELECT user_id FROM users WHERE username = %s", (test_username,))user_id = self.cursor.fetchone()['user_id']self.cursor.execute("INSERT INTO contents (user_id, content_type, title) VALUES (%s, %s, %s)",(user_id, 'text', "测试互动内容"))self.cursor.execute("SELECT LAST_INSERT_ID()")content_id = self.cursor.fetchone()['LAST_INSERT_ID()']# 点赞内容self.cursor.execute("INSERT INTO interactions (user_id, content_id, interaction_type) VALUES (%s, %s, %s)",(user_id, content_id, 'like'))# 验证点赞self.cursor.execute("""SELECT * FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'like'""", (user_id, content_id))like_interaction = self.cursor.fetchone()self.assertIsNotNone(like_interaction)# 收藏内容self.cursor.execute("INSERT INTO interactions (user_id, content_id, interaction_type) VALUES (%s, %s, %s)",(user_id, content_id, 'collect'))# 验证收藏self.cursor.execute("""SELECT * FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'collect'""", (user_id, content_id))collect_interaction = self.cursor.fetchone()self.assertIsNotNone(collect_interaction)# 取消点赞self.cursor.execute("""DELETE FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'like'""", (user_id, content_id))# 验证点赞取消self.cursor.execute("""SELECT * FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'like'""", (user_id, content_id))canceled_like = self.cursor.fetchone()self.assertIsNone(canceled_like)# 取消收藏self.cursor.execute("""DELETE FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'collect'""", (user_id, content_id))# 验证收藏取消self.cursor.execute("""SELECT * FROM interactions WHERE user_id = %s AND content_id = %s AND interaction_type = 'collect'""", (user_id, content_id))canceled_collect = self.cursor.fetchone()self.assertIsNone(canceled_collect)def test_following_system(self):"""测试关注系统功能"""# 创建两个测试用户follower_username = "follower_user_" + self.generate_random_string()follower_email = follower_username + "@example.com"follower_password = "FollowerPassword123!"self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(follower_username, follower_email, hashlib.sha256(follower_password.encode()).hexdigest()))self.cursor.execute("SELECT user_id FROM users WHERE username = %s", (follower_username,))follower_id = self.cursor.fetchone()['user_id']followed_username = "followed_user_" + self.generate_random_string()followed_email = followed_username + "@example.com"followed_password = "FollowedPassword123!"self.cursor.execute("INSERT INTO users (username, email, password_hash) VALUES (%s, %s, %s)",(followed_username, followed_email, hashlib.sha256(followed_password.encode()).hexdigest()))self.cursor.execute("SELECT user_id FROM users WHERE username = %s", (followed_username,))followed_id = self.cursor.fetchone()['user_id']# 关注操作self.cursor.execute("INSERT INTO follows (follower_id, followed_id) VALUES (%s, %s)",(follower_id, followed_id))# 验证关注self.cursor.execute("""SELECT * FROM follows WHERE follower_id = %s AND followed_id = %s""", (follower_id, followed_id))follow_record = self.cursor.fetchone()self.assertIsNotNone(follow_record)# 取消关注self.cursor.execute("""DELETE FROM follows WHERE follower_id = %s AND followed_id = %s""", (follower_id, followed_id))# 验证取消关注self.cursor.execute("""SELECT * FROM follows WHERE follower_id = %s AND followed_id = %s""", (follower_id, followed_id))unfollow_record = self.cursor.fetchone()self.assertIsNone(unfollow_record)if __name__ == "__main__":unittest.main()
测试代码:
-
完整的测试环境准备和清理机制,确保每次测试都在干净的环境中运行
-
覆盖了所有主要的业务逻辑,包括用户管理、内容管理、多媒体文件管理、标签管理、评论系统、互动系统和关注系统
-
严格遵循数据库约束规则,处理好外键约束和唯一键冲突问题
-
测试用例设计全面,包含创建、读取、更新和删除操作
-
使用随机数据生成测试用户和内容,避免测试数据冲突
-
每个测试用例都包含数据验证步骤,确保数据库操作符合预期
相关文章:
内容社区系统开发文档(下)
目录 4 系统测试 4.1 数据库测试设计 测试流程图 测试策略矩阵 4.2 数据库测试内容 测试点 1:数据项增删改查(CRUD)操作 和 数据一致性测试 一、基础数据初始化 二、用户表测试(users) 1. 新增用户 2. 更新…...
什么是迁移学习(Transfer Learning)?
什么是迁移学习(Transfer Learning)? 一句话概括 迁移学习研究如何把一个源领域(source domain)/源任务(source task)中获得的知识迁移到目标领域(target domain)/目标任…...
CMake调试与详细输出选项解析
在使用 CMake 进行项目构建和编译时,--debug-output 和 --verbose 的作用如下: 1. --debug-output 适用阶段:CMake 配置阶段(运行 cmake 命令生成构建系统时)。作用: 启用 CMake 内部的调试输出࿰…...
Elasticsearch进阶篇-DSL
目录 DSL查询 1 快速入门 2 DSL 查询分类 2.1 叶子查询 2.1.1 全文检索查询 语法 举例 2.1.2 精准查询 term 语法 term 示例 range 语法 range 示例 2.2 复合查询 2.2.1 bool查询 举例 2.3 排序 语法 示例 2.4 分页 2.4.1 基础分页 示例 2.4.2 深度分页 …...
2025年全国青少年信息素养大赛初赛真题(算法创意实践挑战赛C++初中组:文末附答案)
2025年全国青少年信息素养大赛初赛真题(算法创意实践挑战赛C++初中组:文末附答案) 一、单项选择题(每题 5 分) C++ 程序流程控制的基本结构不包括以下哪项? A. 分支结构 B. 数据结构 C. 循环结构 D. 顺序结构 以下哪段代码能将数组 int a[4] = {2, 4, 6, 8}; 的所有元素变…...
C++ 二分查找:解锁高效搜索的密码
一、引言 在 C 编程的广阔领域中,数据处理和查找是日常开发中极为常见的操作。想象一下,你有一个包含数百万个数据的有序数组,需要从中快速找到特定的元素,如果采用逐个遍历的方式,效率之低可想而知,而二分…...
YOLO12改进-模块-引入Channel Reduction Attention (CRA)模块 降低模型复杂度,提升复杂场景下的目标定位与分类精度
在语义分割任务中,基于 Transformer 的解码器需要捕获全局上下文信息,但传统自注意力机制(如 SRA)因高分辨率特征图导致计算成本高昂。现有方法多通过降低空间分辨率减少计算量,但未充分优化通道维度。为平衡全局上下文…...
sparkSQL读入csv文件写入mysql
思路 示例 (年龄>18改成>20) mysql的字符集问题 把user改成person “让字符集认识中文”...
如何确定自己的职业发展方向?
引言 确定职业发展方向是一个需要深度自我探索和外部信息结合的过程。以下是系统化的思考框架和行动步骤,帮助你逐步清晰方向: 一、核心问题:职业方向的本质是什么? 职业方向的核心是找到 “你能做什么”(能力&…...
【LLIE专题】基于Retinex理论的transformer暗光增强
Retinexformer: One-stage Retinex-based Transformer for Low-light Image Enhancement(2023,ICCV) 专题介绍一、研究背景二、Retinexformer方法1. 通用Retinex理论2. 作者建立的Retinex理论3. ORF(one stage Retinex-based Framework)4. 网…...
C++多态与虚函数详解——从入门到精通
C多态与虚函数详解——从入门到精通 引言 在C面向对象编程中,多态是一个核心概念,它赋予了程序极大的灵活性和扩展性。本文将通过六个精心设计的实例,深入浅出地讲解C中的多态、虚函数、继承和抽象类等概念,帮助初学者快速理解这…...
自适应Prompt技术:让LLM精准理解用户意图的进阶策略
开发|界面|引擎|交付|副驾——重写全栈法则:AI原生的倍速造应用流 来自全栈程序员 nine 的探索与实践,持续迭代中。 欢迎关注评论私信交流~ 一、核心挑战:传统Prompt的局限性 传统静态Prompt&…...
Java文件读写程序
1.引言 在日常的软件开发中,文件操作是常见的功能之一。不仅要了解如何读写文件,更要知道如何安全地操作文件以避免程序崩溃或数据丢失。这篇文章将深入分析一个简单的 Java 文件读写程序 Top.java,包括其基本实现、潜在问题以及改进建议&am…...
数字电子技术基础(六十)——使用Digital软件绘制脉冲触发的触发器
目录 1 使用Digital软件来绘制脉冲触发的触发器 1.1 使用Digital软件来绘制脉冲触发的SR触发器 1.2 使用Digitial软件绘制脉冲触发的JK触发器 1.3 使用Digital软件绘制脉冲触发D触发器 1 使用Digital软件来绘制脉冲触发的触发器 1.1 使用Digital软件来绘制脉冲触发的SR触发…...
C++学习:六个月从基础到就业——C++20:范围(Ranges)基础
C学习:六个月从基础到就业——C20:范围(Ranges)基础 本文是我C学习之旅系列的第五十一篇技术文章,也是第三阶段"现代C特性"的第十三篇,介绍C20引入的范围(Ranges)库的基础知识。查看完整系列目录了解更多内容。 引言 S…...
【AGI】模型性能评估框架EvalScope
【AGI】模型性能评估框架EvalScope 项目地址:https://github.com/modelscope/evalscope EvalScope 是由阿里巴巴魔搭社区(ModelScope)推出的一款开源模型评估框架,旨在为大语言模型(LLM)和多模态模型提供…...
【老马】离线版金融敏感信息加解密组件开源项目 encryption-local
前言 你是否存在这样的苦恼,数据需要安全存储,但是每个系统大家自己写,很浪费时间。。 每一个子项目各自为政,加解密搞得也无法统一。也许下面这个开源项目可以帮助你。 encryption-local 一个离线版本的金融敏感信息加解密工具…...
利用systemd启动部署在服务器上的web应用
0.背景 系统环境: Ubuntu 22.04 web应用情况: 前后端分类,前端采用react,后端采用fastapi 1.具体配置 1.1 前端配置 开发态运行(启动命令是npm run dev),创建systemd服务文件 sudo nano /etc/systemd/…...
YOLOv5目标构建与损失计算
YOLOv5目标构建与损失计算 YOLOv5目标构建与损失计算构建目标关键步骤解析: 计算损失关键实现细节解析各损失分量说明 YOLOv5目标构建与损失计算 YOLOv5作为单阶段目标检测的经典算法,其高效的检测性能离不开精心设计的训练目标构建和损失计算策略。本文…...
【Linux】ELF与动静态库的“暗黑兵法”:程序是如何跑起来的?
目录 一、什么是库? 1. C标准库(libc) 2. C标准库(libstdc) 二、静态库 1. 静态库的生成 2. 静态库的使用 三、动态库 1. 动态库的生成 2. 动态库的使用 3. 库运行的搜索路径。 (1)原因…...
【图书管理系统】用户注册系统实现详解
引言 本系统允许用户输入用户名和密码,前端通过AJAX请求将数据发送到后端,后端验证并存储用户信息,同时为每个用户创建一个专属图书表。尽管这是一个基础实现,但它展示了前后端分离开发的核心思想。博客还将讨论潜在的优化点&…...
FastDFS分布式文件系统架构学习(一)
FastDFS分布式文件系统架构学习 1. FastDFS简介 FastDFS是一个开源的轻量级分布式文件系统,由淘宝资深架构师余庆设计并开发。它专为互联网应用量身定制,特别适合以中小文件(如图片、文档、音视频等)为载体的在线服务。FastDFS不…...
Oracle 内存优化
Oracle 的内存可以按照共享和私有的角度分为系统全局区和进程全局区,也就是 SGA和 PGA(process global area or private global area)。对于 SGA 区域内的内存来说,是共享的全局的。在 UNIX 上,必须为 Oracle 设置共享内存段(可以是一个或者多…...
算法题(149):矩阵消除游戏
审题: 本题需要我们找到消除矩阵行与列后可以获得的最大权值 思路: 方法一:贪心二进制枚举 这里的矩阵消除时,行与列的消除会互相影响,所以如果我们先统计所有行和列的总和,然后选择消除最大的那一行/列&am…...
AI:NLP 情感分析
💬 从零开始掌握情感分析:NLP 初学者实战指南 本文适合自然语言处理(NLP)入门者,聚焦于最热门应用之一——情感分析(Sentiment Analysis)。无论你是学生、工程师,还是数据爱好者,都可以通过本文了解情感分析的原理、方法和实现技巧。 🧠 一、什么是情感分析? 情感…...
LearnOpenGL---着色器
着色器的例子 文章目录 着色器的例子1.颜色变化的三角形2.构造三个顶点颜色不同的一个三角形 1.颜色变化的三角形 #include <glad/glad.h> #include <GLFW/glfw3.h>#include <iostream> #include <cmath>void framebuffer_size_callback(GLFWwindow* …...
计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 13.几何着色器(一)修改顶点
几何着色器 以下是OpenGL图像管线的主要阶段: 几何着色器(Geometry Shader) 几何着色器是OpenGL管线中的一个可选阶段,位于顶点着色器和片段着色器之间。它能够动态地生成或修改图元(primitives)。 主…...
如何利用 Java 爬虫获得某书笔记详情:实战指南
在知识分享和学习的领域,许多平台提供了丰富的书籍笔记和学习资源。通过 Java 爬虫技术,我们可以高效地获取这些笔记的详细信息,以便进行进一步的分析和整理。本文将详细介绍如何利用 Java 爬虫获取某书笔记详情,并提供完整的代码…...
【关联git本地仓库,上传项目到github】
目录 1.下载git2.绑定用户3.git本地与远程仓库交互4.github项目创建5.上传本地项目到github6.完结撒花❀❀❀!!! 1.下载git git下载地址:https://git-scm.com/downloads 下载安装后创建快捷地址:(此处比较…...
计算机科技笔记: 容错计算机设计05 n模冗余系统 TMR 三模冗余系统
NMR(N-Modular Redundancy,N 模冗余)是一种通用的容错设计架构,通过引入 N 个冗余模块(N ≥ 3 且为奇数),并采用多数投票机制,来提升系统的容错能力与可靠性。单个模块如果可靠性小于…...
配置代理服务器访问github、google
配置代理服务器访问github、google 背景与原理配置环境配置步骤云主机配置Windows客户端创建SSH隧道安装 Windows 内置 OpenSSHssh config 配置文件创建动态代理隧道 浏览器代理设置 验证浏览器访问google、githubssh 访问github 背景与原理 由于网络政策限制,中国…...
Java API学习笔记
一.类 1. String 类 不可变性:String对象创建后不可修改,每次操作返回新对象 String str "Hello"; str.length(); str.charAt(0); str.substring(1, 4); str.indexOf("l"); str.equals("hel…...
C++ map容器: 插入操作
1. map插入操作基础 map是C STL中的关联容器,存储键值对(key-value pairs)。插入元素时有四种主要方式,各有特点: 1.1 头文件与声明 #include <map> using namespace std;map<int, string> mapStu; // 键为int,值…...
Linux SSH 远程连接全攻略:从加密原理到实战配置(含图解)
一、SSH 加密体系核心理论 (一)对称加密与非对称加密对比解析 1. 加密算法分类与应用场景 类型代表算法密钥数量加密速度安全性特点典型用途对称加密AES、3DES1 个★★★★☆密钥传输风险高会话数据加密非对称加密RSA、ECC2 个★★☆☆☆公钥可公开&a…...
项目制作流程
一、使用 CRA 创建项目 npx create-react-app name 二、按照业务规范整理项目目录 (重点src目录) 三、安装插件 npm install sass -Dnpm install antd --savenpm install react-router-dom 四、配置基础路由 Router 1. 安装路由包 react-router-dom …...
ctr查看镜像
# 拉取镜像到 k8s.io 命名空间 sudo nerdctl --namespace k8s.io pull nginx:1.23.4 # 验证镜像是否已下载 sudo nerdctl --namespace k8s.io images 下载镜像到k8s.io名称空间下 nerdctl --namespace k8s.io pull zookeeper:3.6.2 sudo ctr image pull --namespace k8s.io …...
【深度学习基础】从感知机到多层神经网络:模型原理、结构与计算过程全解析
【深度学习基础】从感知机到多层神经网络:模型原理、结构与计算过程全解析 1. 引言 神经网络的重要性: 作为人工智能的核心技术之一,神经网络通过模拟人脑神经元的工作机制,成为解决复杂模式识别、预测和决策任务的利器。从图像分…...
discuz X3.5批量新建用户
<?php define(IN_DISCUZ, true); require ./source/class/class_core.php; // 确保管理员权限(可选,增加安全性)删除这一段加粗则可以直接使用. if ($_G[adminid] ! 1) { exit(Access denied. Only admin allowed.); } C::app()->…...
symfonos: 1靶场
symfonos: 1 来自 <https://www.vulnhub.com/entry/symfonos-1,322/> 1,将两台虚拟机网络连接都改为NAT模式 2,攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182,靶场IP192.168.23.252 3&…...
C# String 格式说明符
标准格式说明符数字格式说明符C 或 c:货币格式D 或 d:十进制数字格式E 或 e:科学计数法格式。F 或 f:固定点格式G 或 g:常规格式N 或 n:数字格式P 或 p:百分比格式X 或 x:十六进制格…...
Python高级特性深度解析:从熟练到精通的跃迁之路
Python高级特性深度解析:从熟练到精通的跃迁之路 引言 对于已经掌握Python基础语法的开发者而言,如何突破瓶颈进入高手行列?本文将从Python的高级特性入手,深入剖析那些能让代码更优雅、效率更高的技术点,助你完成从…...
【微信小程序 + 高德地图API 】键入关键字搜索地址,获取经纬度等
前言 又到熟悉的前言,接到个需求,要引入高德地图api,我就记录一下,要是有帮助记得点赞、收藏、关注😁。 后续有时间会慢慢完善一些文章:(画饼时间) map组件自定义气泡、mark标记点…...
贪心、分治和回溯算法
1. 贪心算法 1.1. 贪心算法的概念 定义:在求解过程中,始终做出当前状态下看起来“最优”的选择,不回退。核心思想:每一步都选择当前最优解,期望最后得到全局最优解。 适用问题的特征: 问题可以分解成多个…...
window自带截图快捷键
Win Shift S:按此组合键后,会出现截图模式选择框,可选择矩形截图、任意形状截图、窗口截图和全屏幕截图,然后使用 “Ctrl V” 粘贴截图内容...
简单使用Slidev和PPTist
简单使用Slidev和PPTist 1 简介 前端PPT制作有很多优秀的工具包,例如:Slidev、revealjs、PPTist等,Slidev对Markdown格式支持较好,适合与大模型结合使用,选哟二次封装;revealjs适合做数据切换,…...
1.2.2
某智慧养老平台的心率监测模块目前存在数据准确性不高、异常预警响应慢等问题,影响了老年人健康监测的体验和服务质量。作为人工智能训练师,你需要结合业务知识和人工智能技术,对该模块进行优化设计与实现。 (1)列出心…...
LeeCode 101.对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。 提示: 树中节点数目在范围 [1, 1000] 内-100 < Node.val < 100 进阶:你可以运用递归和迭代两种方法解决这个问题吗? 答案 && 测试代码: #include &…...
面向GIS的Android studio移动开发(二)--在地图上绘制电子围栏
电子围栏,校园跑的常客,也是定位打卡必不可少的东西 主要代码: 创建电子围栏代码 // 添加多边形地理围栏(兼容2023版SDK)private void addPolygon(String fenceName, List<LatLng> points) {if (points null…...
《从零开始:Spring Cloud Eureka 配置与服务注册全流程》
关于Eureka的学习,主要学习如何搭建Eureka,将order-service和product-service都注册到Eureka。 1.为什么使用Eureka? 我在实现一个查询订单功能时,希望可以根据订单中productId去获取对应商品的详细信息,但是产品服务和订单服…...
能力验证及大练兵活动第一期
计算机 请根据计算机检材,回答以下问题: (10道题,共19.0分) 1. 计算机中曾挂载的Bitlocker加密分区的恢复密钥后6位为?(答案格式:6位数字) (1.0分) 答案:700755 2. 请写出曾远程连…...