2024秋软件工程结对作业(第二次之程序实现)
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2024 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2024/homework/13281 |
这个作业的目标 | 根据需求分析和原型设计,通过代码实现项目互通小程序 |
学号 | 102202131 |
合作伙伴 | 102202132 林鑫 |
博客链接 | https://www.cnblogs.com/PZn000/p/18457483 |
合作伙伴博客链接 | https://www.cnblogs.com/zhengbingzhi/p/18457479 |
github项目仓库地址 | https://github.com/PZn000/102202131-102202132 |
一、具体分工
102202132 郑冰智
-
模块开发:
- 聊天论坛模块:负责开发小程序的聊天论坛功能。实现聊天信息的存储、发布和查询,通过云数据库和云函数进行数据处理。在前端提供实时更新的聊天界面,方便用户交流和讨论项目。
- 我的收藏模块:开发“我的收藏”功能,实现项目的收藏和管理。与后端交互,将收藏信息存储在云数据库中,并在前端提供收藏列表展示和删除功能。
- 主页模块:设计并实现主页界面,包括搜索栏、项目发布按钮和项目列表展示。与后端接口配合,实现搜索栏的高效检索功能,项目发布按钮触发后端数据录入操作,项目列表从云数据库获取数据并在前端展示。
- 我的项目模块:开发“我的项目”功能,自动查询用户参与的项目。通过前后端通信,从云数据库获取用户参与项目信息并在前端呈现。
-
后端开发:
- 云数据库配置:合理规划云数据库结构,为用户信息、项目信息等数据创建相应的数据表和字段。设置索引以提高数据查询效率,确保数据存储的安全性和稳定性。
- 云函数开发:编写云函数实现用户认证、项目发布、项目查询等业务逻辑。利用云函数的触发机制,实时处理数据变化并通知前端更新界面。
-
特色功能:
- 我的项目自动查询功能:通过优化数据库查询语句和前后端通信机制,实现快速准确地自动查询用户参与的项目。在前端提供清晰的项目列表展示,方便用户管理和查看自己参与的项目。
- 数据安全特色:加强用户密码加密存储,采用多因素认证等安全措施,保障用户数据的安全性。对敏感数据进行加密传输,防止数据泄露。
-
博客撰写:
- 记录小程序开发过程中的技术挑战和解决方案,分享开发经验和心得。撰写关于小程序功能介绍、使用教程等内容的博客文章,为用户提供使用指导和帮助。
- 定期更新博客,回应用户反馈和问题,与用户进行互动交流,不断改进小程序的功能和用户体验。
102202131 林鑫
-
模块开发:
- 用户认证模块:负责开发小程序的登入、注册和找回密码界面。通过前后端交互,将用户输入信息发送至后端,后端利用云数据库存储用户信息并进行验证。采用加密算法保障用户密码安全,实现身份验证机制以判断用户是否存在。
- 聊天论坛模块:负责开发小程序的聊天论坛功能。实现聊天信息的存储、发布和查询,通过云数据库和云函数进行数据处理。在前端提供实时更新的聊天界面,方便用户交流和讨论项目。
- 项目发布模块:负责项目发布功能的实现。在前端提供简洁易用的项目发布界面,用户可以输入项目名称、描述、所需专业等信息。通过与后端接口交互,将项目信息存储到云数据库中,并触发相关的云函数进行数据处理和通知。确保项目发布的流程顺畅,数据准确存储。
- 项目申请加入模块:开发项目申请加入功能。在前端展示项目详情页面时,提供申请加入按钮。用户点击后,弹出申请信息输入框,用户填写相关信息后提交申请。后端接收申请信息,进行数据校验和处理,将申请信息存储到项目对应的数据库表中,
-
页面优化:
- 界面美化:运用专业的设计工具和技术,对小程序的界面进行美化设计。选择合适的色彩搭配、字体样式和图标,提升小程序的视觉效果和用户体验。
- 弹窗和滑动优化:优化小程序中的弹窗效果,使其更加简洁美观、易于操作。对页面滑动效果进行优化,提高页面切换的流畅性和响应速度。
-
小程序测试:
- 功能测试:对小程序的各个功能模块进行全面的功能测试,确保功能的正确性和稳定性。编写测试用例,覆盖各种场景和用户操作,及时发现并修复功能缺陷。
- 性能测试:进行小程序的性能测试,包括页面加载速度、响应时间等方面的测试。优化小程序的性能,提高用户使用的流畅性和满意度。
-
博客优化:
- 对成员一撰写的博客文章进行优化,提高文章的可读性和专业性。检查文章中的语法错误和排版问题,确保文章质量。
- 根据大家对小程序的反馈和建议,及时转达给开发团队,促进小程序的不断改进和完善。
二、PSP 表格
PSP2.1 Personal Software Process Stages | 预估耗时(小时) | 实际耗时(小时) |
---|---|---|
Planning (计划) | 2 | 2.5 |
Estimate (估计这个任务需要多少时间) | 48 | 48 |
Development (开发) | 15 | 15 |
Analysis (需求分析,包括学习新技术) | 3 | 3.5 |
Design Review (设计复审) | 1.5 | 1.5 |
Coding Standard (代码规范,为开发制定规范) | 1 | 1.5 |
Design (具体设计) | 2.5 | 3 |
Coding (具体编码) | 12 | 14 |
Code Review (代码复审) | 2 | 3 |
Test (测试,自我测试,修改代码,提交修改) | 4 | 4 |
Reporting(报告) | 2 | 1.5 |
Test Report (测试报告) | 1.5 | 1.5 |
Size Measurement (计算工作量) | 0.5 | 0.5 |
Postmortem & Process Improvement Plan (总结) | 0.5 | 0.75 |
合计 | 48 | 52.25 |
三、解题思路与设计实现说明
一、需求分析
(一)功能需求(附带伪代码)
- 登入注册功能:
- 用户可以通过输入用户名、密码进行注册,注册成功后可以使用用户名和密码进行登录。
- 代码实现思路:前端通过表单收集用户输入的注册信息,使用表单验证技术确保信息格式正确。然后通过 axios 等工具向后端接口发送 POST 请求,携带用户信息。后端接收到请求后,将用户信息存储到数据库中,同时对密码进行加密处理。登录时,前端同样发送请求,后端验证用户名和密码是否匹配,如果匹配则返回登录成功的响应。
# 后端
def get_projects_from_database():
"""
从数据库获取项目列表。
"""
pass
# 前端
def display_projects(projects):
"""
展示项目列表。
"""
pass
- 主页项目分布功能:
- 在主页上展示项目列表,包括项目名称、描述等信息。用户可以浏览项目列表,了解不同的项目。
- 代码实现思路:后端从数据库中读取项目信息,通过接口将项目列表数据返回给前端。前端使用列表渲染的方式展示项目列表,每个项目可以点击进入项目详情页面。
# 前端
def get_search_keyword():
"""
获取用户输入的搜索关键词。
"""
pass
def send_search_request(keyword):
"""
发送搜索请求。
"""
pass
# 后端
def search_projects(keyword):
"""
根据关键词在数据库中搜索项目。
"""
pass
- 主页搜索功能:
- 用户可以在主页的搜索栏中输入关键词,搜索相关的项目。
- 代码实现思路:前端获取用户输入的搜索关键词,发送请求到后端。后端使用数据库的搜索功能,如倒排索引等,根据关键词在项目信息中进行检索,然后将搜索结果返回给前端进行展示。
# 前端
def get_search_keyword():
"""
获取用户输入的搜索关键词。
"""
pass
def send_search_request(keyword):
"""
发送搜索请求。
"""
pass
# 后端
def search_projects(keyword):
"""
根据关键词在数据库中搜索项目。
"""
pass
- 论坛讨论功能:
- 用户可以在论坛中发布消息、回复消息,进行项目相关的讨论。
- 代码实现思路:前端提供论坛页面,用户输入消息后发送请求到后端。后端将消息存储到数据库中,并通过实时更新的技术,如 WebSocket 等,将新消息推送给所有在线的用户。
# 前端
def get_message_input():
"""
获取用户输入的消息。
"""
pass
def send_message_request(message):
"""
发送消息请求。
"""
pass
# 后端
def save_message_to_database(message):
"""
将消息保存到数据库。
"""
pass
def push_new_message_to_users(new_message):
"""
将新消息推送给用户。
"""
pass
- 我的界面收藏模块和参与项目模块:
- 收藏模块:用户可以收藏感兴趣的项目,在我的收藏页面中查看和管理收藏的项目。
- 参与项目模块:展示用户参与的项目列表,方便用户快速访问自己参与的项目。
- 代码实现思路:收藏模块,前端通过接口将收藏操作发送到后端,后端将收藏信息存储到数据库中。在我的收藏页面,从数据库中读取收藏信息并展示给用户。参与项目模块,后端通过数据库查询和关联技术,获取用户参与的项目信息,返回给前端展示。
# 前端
def send_favorite_request(project_id):
"""
发送收藏请求。
"""
pass
# 后端
def save_favorite_to_database(user_id, project_id):
"""
将项目收藏信息保存到数据库。
"""
pass
def get_favorites_from_database(user_id):
"""
从数据库获取用户收藏的项目。
"""
pass
#后端
def get_user_participated_projects(user_id):
"""
获取用户参与的项目。
"""
pass
(二)个人信息分析(伪代码)
- 全局变量:可以设置一些全局变量来存储用户的登录状态、用户信息等。例如,在用户登录成功后,将用户信息存储在全局变量中,方便在不同页面中使用。
- 代码实现思路:在 Vue.js 项目中,可以使用 Vuex 等状态管理工具来管理全局变量。在用户登录成功后,将用户信息存储到 Vuex 的 state 中,在需要使用用户信息的组件中,可以通过
mapState
等方式获取全局变量中的用户信息。
- 代码实现思路:在 Vue.js 项目中,可以使用 Vuex 等状态管理工具来管理全局变量。在用户登录成功后,将用户信息存储到 Vuex 的 state 中,在需要使用用户信息的组件中,可以通过
// 定义全局状态存储
const globalState = {
isLoggedIn: false,
userInfo: null
};
// 设置登录状态和用户信息
function setLoginStatus(status, info) {
globalState.isLoggedIn = status;
globalState.userInfo = info;
}
// 获取登录状态和用户信息
function getLoginStatus() {
return globalState.isLoggedIn;
}
function getUserInfo() {
return globalState.userInfo;
}
- 数据库:存储用户信息、项目信息、聊天信息、收藏信息等。合理设计数据库结构,确保数据的存储和查询效率。
- 代码实现思路:根据不同的功能需求,设计相应的数据表结构。例如,用户信息表可以包括用户名、密码、邮箱等字段;项目信息表可以包括项目名称、描述、发布者等字段。使用云数据库等工具,通过设置索引、优化查询语句等方式提高数据存储和查询的性能。
// 添加用户信息到数据库
function addUserToDatabase(username, password, email) {
// 使用云数据库 API 添加用户信息
}
// 查询用户信息
function queryUserFromDatabase(username) {
// 使用云数据库 API 根据用户名查询用户信息
}
// 添加项目信息到数据库
function addProjectToDatabase(name, description, publisher) {
// 使用云数据库 API 添加项目信息
}
// 查询项目信息
function queryProjectsFromDatabase() {
// 使用云数据库 API 查询项目信息
}
(三)性能优化分析
- 优化代码,更换部分函数以及调用云数据库的方法等,提高小程序性能。例如,优化数据库查询语句,避免不必要的查询和数据加载。
- 代码实现思路:对代码进行性能分析,找出性能瓶颈。如果数据库查询耗时较长,可以通过优化查询语句、添加索引等方式提高查询效率。同时,检查代码中是否存在不必要的循环、重复计算等问题,进行优化。
- 对于数据不同步的问题,增加刷新功能,确保用户能够及时看到最新的数据。
- 代码实现思路:在前端页面中添加刷新按钮,用户点击刷新按钮时,发送请求到后端获取最新的数据。后端可以通过缓存技术等方式,提高数据的获取速度,确保数据的实时性。
4. 关键实现流程图
- 流程图:
- 项目信息数据流图:
5. 代码片段:
- 代码片段1:通过数据库申请项目并输出项目:
const app = getApp();
const db = wx.cloud.database(); // 获取数据库引用
Page({
data: {
projectName: '',
projectType: '',
majorsRequired: '',
timeSchedule: '',
contactInfo: '',
memberRequirements: '',
projectIntroduction: ''
},
inputProjectName: function(e) { this.setData({ projectName: e.detail.value }); },
inputProjectType: function(e) { this.setData({ projectType: e.detail.value }); },
inputMajorsRequired: function(e) { this.setData({ majorsRequired: e.detail.value }); },
inputTimeSchedule: function(e) { this.setData({ timeSchedule: e.detail.value }); },
inputContactInfo: function(e) { this.setData({ contactInfo: e.detail.value }); },
inputMemberRequirements: function(e) { this.setData({ memberRequirements: e.detail.value }); },
inputProjectIntroduction: function(e) { this.setData({ projectIntroduction: e.detail.value }); },
// 提交项目到数据库
submitProject: function() {
if (this.validateInput()) {
let projectData = {
user: app.globalData.user,
projectName: this.data.projectName,
projectType: this.data.projectType,
majorsRequired: this.data.majorsRequired,
timeSchedule: this.data.timeSchedule,
contactInfo: this.data.contactInfo,
memberRequirements: this.data.memberRequirements,
projectIntroduction: this.data.projectIntroduction,
participator: []
};
db.collection('project').add({
data: projectData,
success: function(res) {
wx.showToast({ title: '提交成功', icon: 'success', duration: 2000 });
wx.navigateBack(); // 返回上一页
},
fail: function(error) {
wx.showToast({ title: '提交失败,请重试', icon: 'none', duration: 2000 });
}
});
}
},
// 输入验证函数
validateInput: function() {
let { projectName, projectType, majorsRequired, timeSchedule, contactInfo, memberRequirements, projectIntroduction } = this.data;
let isValid = true;
if (!projectName.trim()) { wx.showToast({ title: '请输入项目名称', icon: 'none' }); isValid = false; }
if (!projectType.trim()) { wx.showToast({ title: '请输入项目类型', icon: 'none' }); isValid = false; }
if (!majorsRequired.trim()) { wx.showToast({ title: '请输入所需专业', icon: 'none' }); isValid = false; }
if (!timeSchedule.trim()) { wx.showToast({ title: '请输入时间安排', icon: 'none' }); isValid = false; }
if (!contactInfo.trim()) { wx.showToast({ title: '请输入联系方式', icon: 'none' }); isValid = false; }
if (!memberRequirements.trim()) { wx.showToast({ title: '请输入成员要求', icon: 'none' }); isValid = false; }
if (!projectIntroduction.trim()) { wx.showToast({ title: '请输入项目简介', icon: 'none' }); isValid = false; }
return isValid;
}
});
--------------------------------------------------------------------------------------------------------------------------------------------
// 从数据库加载项目
loadProjectsFromDB: function(callback) {
const db = wx.cloud.database();
const that = this;
db.collection('project').get({
success: function(res) {
that.setData({ allCategory: res.data });
if (callback) callback();
},
fail: function(error) {
wx.showToast({ title: '加载项目失败', icon: 'none' });
if (callback) callback();
}
});
},
项目数据提交:
用户输入项目信息后,调用 submitProject 函数,先通过 validateInput 验证必填项。验证成功后,将项目数据作为 JSON 对象存入云数据库的 project 集合。数据库操作使用 wx.cloud.database().collection('project').add(),成功提交后提示并返回上一页。
项目数据展示:
主页加载时,onLoad 函数调用 loadProjectsFromDB,从数据库提取项目并存储到 allCategory,项目数据展示在页面上。
- 代码片段2:搜索功能:
// 处理搜索框输入
handleInput: function(e) {
const value = e.detail.value;
this.setData({
searchKeyword: value
});
// 如果搜索框为空,重新加载所有项目
if (value.trim() === '') {
this.loadProjectsFromDB(); // 重新加载所有项目
}
},
// 处理搜索图标点击
handleSearch: function() {
this.setData({
isCategory: true
});
const keyword = this.data.searchKeyword.trim().toLowerCase();
if (keyword === '') {
// 如果关键词为空,恢复显示所有项目
this.loadProjectsFromDB(); // 重新加载所有项目
return;
}
// 通过关键词筛选项目
let results = this.data.allCategory.filter(project => {
return Object.values(project).some(prop =>
prop.toString().toLowerCase().includes(keyword)
);
});
if (results.length === 0) {
wx.showToast({
title: '未找到匹配内容',
icon: 'none'
});
}
this.setData({
searchResults: results
});
},
搜索栏搜索
点击分类搜索
搜索框输入处理 (handleInput):
用户输入时,内容会存入 searchKeyword。若搜索框为空(清空输入),系统调用 loadProjectsFromDB 重新加载并显示所有项目。
点击搜索按钮处理 (handleSearch):
点击搜索按钮后,isCategory 设置为 true,获取并小写化用户输入的关键词。如果为空,恢复显示所有项目;否则,根据关键词在 allCategory 中进行模糊匹配。若无结果,显示“未找到匹配内容”,否则更新 searchResults 以展示匹配的项目。
关键点:
模糊匹配:项目字段与关键词进行模糊匹配,使用 includes 查找。
实时反馈:根据用户输入动态过滤显示项目。
空输入恢复:若输入为空,恢复项目列表。
- 代码片段3:刷新功能:
// 点击刷新图片时触发,从数据库重新加载项目
handleRefreshTap: function() {
this.setData({
isCategory: false // 将 isCategory 设置为 false,表明当前处于非分类或搜索状态
});
console.log(this.data.isCategory);
// 显示顶部加载动画
wx.showNavigationBarLoading();
// 重新加载项目数据
this.loadProjectsFromDB(() => {
// 隐藏顶部加载动画
wx.hideNavigationBarLoading();
// 显示刷新成功的提示
wx.showToast({
title: '刷新成功',
icon: 'success'
});
});
}
代码解释:
状态更新:将 isCategory 设置为 false,表明当前状态不是分类或搜索状态。
显示加载动画:调用 wx.showNavigationBarLoading() 在页面顶部显示加载动画,提示用户正在刷新。
重新加载项目:调用 loadProjectsFromDB() 函数从数据库重新获取项目数据。
加载完成处理:
隐藏加载动画:调用 wx.hideNavigationBarLoading() 停止顶部加载动画。
显示提示信息:刷新完成后,通过 wx.showToast() 显示 "刷新成功" 的提示消息,告知用户刷新已完成。
关键点:
用户反馈:通过顶部加载动画和提示信息,提供了实时的用户反馈,改善用户体验。
数据重新加载:每次点击刷新按钮时,项目数据会从数据库中重新提取并更新显示。
四、附加特点设计与展示
-特色部分:搜索功能具有历史记录和猜你想搜的功能,可以根据不同用户的搜索记录等等来判断个人喜好:
代码:
updateSuggestedTags: function () {
const { recentSearches, tagLibrary } = this.data;
let suggestedTags = [];
if (recentSearches.length > 0) {
// 遍历最近搜索记录,查找相关标签
recentSearches.forEach(search => {
Object.keys(tagLibrary).forEach(category => {
if (search.includes(category)) {
// 如果搜索关键词匹配某个类别,获取相关标签
suggestedTags = [...new Set([...suggestedTags,...tagLibrary[category]])];
}
});
});
}
// 如果没有匹配到标签,则从分类中随机挑选一些标签
if (suggestedTags.length === 0) {
const shuffledCategories = this.data.categories.sort(() => 0.5 - Math.random());
suggestedTags = shuffledCategories.slice(0, 6); // 随机选取6个标签
}
this.setData({
suggestedTags: suggestedTags
});
},
handleInput: function (e) {
const value = e.detail.value;
this.setData({
searchKeyword: value
});
// 如果搜索框为空,重新加载所有项目并隐藏搜索记录
if (value.trim() === '') {
this.setData({
showRecentSearches: false // 隐藏最近搜索
});
this.loadProjectsFromDB(); // 重新加载所有项目
}
},
handleTagTap: function (e) {
const tag = e.currentTarget.dataset.tag;
this.setData({
searchKeyword: tag
});
this.handleSearch(); // 直接进行搜索
},
handleDeleteSearch: function (e) {
const keywordToDelete = e.currentTarget.dataset.keyword;
let recentSearches = this.data.recentSearches.filter(item => item!== keywordToDelete);
this.setData({
recentSearches: recentSearches
});
// 更新猜你想搜标签
this.updateSuggestedTags();
},
更新猜你想搜标签的函数:这个函数用于更新猜你想搜的标签列表。如果最近搜索记录不为空,遍历最近搜索记录,检查是否包含在tagLibrary中的学科名称,如果包含,则将对应的相关标签添加到suggestedTags中。如果没有匹配到任何标签,则从分类列表中随机选取 6 个作为猜你想搜的标签。最后,通过setData更新suggestedTags数据。
处理猜你想搜标签点击的函数:当猜你想搜的标签被点击时,将标签设置为搜索关键词,并调用搜索函数进行搜索。
删除单个搜索记录的函数:这个函数在删除单个搜索记录时被调用。根据点击的关键词从最近搜索记录中删除该关键词,然后更新最近搜索记录数据,并更新猜你想搜的标签。
成果展示:
五、目录说明和使用说明
1. 目录结构
卷 新加卷 的文件夹 PATH 列表
卷序列号为 9A71-4E3F
E:.
+---102202131-102202132
+---miniprogram_npm
| +---@cloudbase
| | +---database
| | +---node-sdk
| | +---signature-nodejs
| | \---wx-cloud-client-sdk
| +---@tootallnate
| | \---once
| +---agent-base
| +---agentkeepalive
| +---asynckit
| +---axios
| +---base64-js
| +---bson
| +---buffer
| +---buffer-equal-constant-time
| +---call-bind
| +---clone
| +---combined-stream
| +---debug
| +---define-data-property
| +---delayed-stream
| +---ecdsa-sig-formatter
| +---es-define-property
| +---es-errors
| +---follow-redirects
| +---form-data
| +---function-bind
| +---get-intrinsic
| +---gopd
| +---has-property-descriptors
| +---has-proto
| +---has-symbols
| +---hasown
| +---http-proxy-agent
| +---https-proxy-agent
| +---humanize-ms
| +---ieee754
| +---is-stream
| +---jsonwebtoken
| +---jwa
| +---jws
| +---lodash.clonedeep
| +---lodash.includes
| +---lodash.isboolean
| +---lodash.isinteger
| +---lodash.isnumber
| +---lodash.isplainobject
| +---lodash.isstring
| +---lodash.once
| +---lodash.set
| +---lodash.unset
| +---mime-db
| +---mime-types
| +---ms
| +---object-inspect
| +---punycode
| +---qs
| +---regenerator-runtime
| +---retry
| +---safe-buffer
| +---sax
| +---semver
| +---set-function-length
| +---side-channel
| +---url
| +---xml2js
| \---xmlbuilder
+---node_modules
| +---.bin
| +---@cloudbase
| | +---database
| | | +---.trunk
| | | | \---configs
| | | +---dist
| | | | \---commonjs
| | | | +---commands
| | | | +---config
| | | | +---const
| | | | +---geo
| | | | +---helper
| | | | +---ObjectId
| | | | +---realtime
| | | | +---regexp
| | | | +---serializer
| | | | +---serverDate
| | | | +---transaction
| | | | +---typings
| | | | \---utils
| | | \---src
| | | +---commands
| | | +---config
| | | +---const
| | | +---geo
| | | +---helper
| | | +---ObjectId
| | | +---realtime
| | | +---regexp
| | | +---serializer
| | | +---serverDate
| | | +---transaction
| | | +---typings
| | | \---utils
| | +---node-sdk
| | | +---dist
| | | | +---analytics
| | | | +---auth
| | | | +---const
| | | | +---database
| | | | +---functions
| | | | +---logger
| | | | +---notification
| | | | +---storage
| | | | +---utils
| | | | \---wx
| | | +---src
| | | | +---analytics
| | | | +---auth
| | | | +---const
| | | | +---database
| | | | +---functions
| | | | +---logger
| | | | +---notification
| | | | +---storage
| | | | +---utils
| | | | \---wx
| | | \---types
| | +---signature-nodejs
| | | +---lib
| | | \---typings
| | \---wx-cloud-client-sdk
| | \---lib
| | +---api
| | +---orm
| | \---types
| +---@tootallnate
| | \---once
| | \---dist
| +---@types
| | \---clone
| +---agent-base
| | +---dist
| | | \---src
| | \---src
| +---agentkeepalive
| | \---lib
| +---asynckit
| | \---lib
| +---axios
| | +---dist
| | \---lib
| | +---adapters
| | +---cancel
| | +---core
| | +---defaults
| | | \---env
| | +---env
| | \---helpers
| +---base64-js
| +---bson
| | +---dist
| | +---etc
| | +---lib
| | | +---parser
| | | \---utils
| | \---src
| | +---parser
| | \---utils
| +---buffer
| +---buffer-equal-constant-time
| +---call-bind
| | +---.github
| | \---test
| +---clone
| +---combined-stream
| | \---lib
| +---debug
| | \---src
| +---define-data-property
| | +---.github
| | \---test
| +---delayed-stream
| | \---lib
| +---ecdsa-sig-formatter
| | \---src
| +---es-define-property
| | +---.github
| | \---test
| +---es-errors
| | +---.github
| | \---test
| +---follow-redirects
| +---form-data
| | \---lib
| +---function-bind
| | +---.github
| | \---test
| +---get-intrinsic
| | +---.github
| | \---test
| +---gopd
| | +---.github
| | \---test
| +---has-property-descriptors
| | +---.github
| | \---test
| +---has-proto
| | +---.github
| | \---test
| +---has-symbols
| | +---.github
| | \---test
| | \---shams
| +---hasown
| | \---.github
| +---http-proxy-agent
| | \---dist
| +---https-proxy-agent
| | \---dist
| +---humanize-ms
| +---ieee754
| +---is-stream
| +---jsonwebtoken
| | \---lib
| +---jwa
| +---jws
| | \---lib
| +---lodash.clonedeep
| +---lodash.includes
| +---lodash.isboolean
| +---lodash.isinteger
| +---lodash.isnumber
| +---lodash.isplainobject
| +---lodash.isstring
| +---lodash.once
| +---lodash.set
| +---lodash.unset
| +---mime-db
| +---mime-types
| +---ms
| +---object-inspect
| | +---.github
| | +---example
| | \---test
| | \---browser
| +---punycode
| +---qs
| | +---.github
| | +---dist
| | +---lib
| | \---test
| +---regenerator-runtime
| +---retry
| | +---example
| | \---lib
| +---safe-buffer
| +---sax
| | \---lib
| +---semver
| | +---bin
| | +---classes
| | +---functions
| | +---internal
| | \---ranges
| +---set-function-length
| | \---.github
| +---side-channel
| | +---.github
| | \---test
| +---url
| | \---test
| +---xml2js
| | \---lib
| \---xmlbuilder
| +---lib
| \---typings
+---pages
| +---addProject
| +---chatPage
| +---collectionPage
| | \---image
| +---discussionArea
| +---forgotPassword
| +---forum
| | \---image
| +---homePage
| | \---image
| +---index
| +---joinedProject
| +---loginRegisterPage
| +---logs
| +---mainPage
| +---messagePage
| | \---image
| +---my
| | \---image
| +---myPage
| | \---images
| +---projectDetail
| | \---images
| +---projectResults
| +---test
| \---text
\---utils
2. 使用步骤:
- 获取小程序二维码
向开发团队申请成为体验者。 - 扫码进入小程序
- 打开手机微信,使用“扫一扫”功能扫描测试版二维码。
- 微信会自动识别二维码并打开小程序。
- 功能测试
- 登录注册功能:
- 尝试使用不同的用户名、密码组合进行登录和注册操作,检查输入验证和错误提示是否正确。
- 测试忘记密码功能,验证找回密码的流程是否顺畅。
- 项目发布功能:
- 检查是否能够顺利发布项目。
- 确认发布后的项目是否能在项目列表中正确显示,并且信息完整准确。
- 项目申请加入功能:
- 申请加入不同的项目,检查申请信息的填写和提交过程是否简便流畅。
- 观察申请提交后,系统是否有相应的提示和反馈。
- 聊天论坛功能:
- 能否收到不同测试人员在论坛发布的消息。
- 我的收藏功能:
- 收藏项目,检查收藏列表的更新是否及时。
- 性能测试
- 在使用小程序的过程中,注意观察页面加载速度、操作响应时间等性能指标。
- 打开不同的页面,记录加载时间,判断是否在可接受范围内。
- 进行频繁的操作,如快速切换页面、发送多条消息等,观察小程序是否出现卡顿或崩溃现象。
- 问题反馈
- 如果在测试过程中发现问题,及时记录问题的详细情况。
- 包括操作步骤、出现问题的页面、错误现象、手机型号和微信版本等信息。
- 将问题反馈给开发团队,可以通过邮件、项目管理工具或直接沟通的方式,以便开发团队及时修复问题。
六、单元测试
为了测试上述代码,我选择使用 Jest 作为单元测试工具。Jest 是一个流行的 JavaScript 测试框架,支持模块化测试、异步测试和快照测试,适合与小程序进行集成。以下是对单元测试的解释、部分代码示例和测试数据构造思路。
1. 测试工具与学习方式【4分】
选用的测试工具
Jest 是我选择的测试工具,主要原因包括:
- 简单易用:Jest 的 API 简单且直观,适合初学者。
- 良好的社区支持:有丰富的文档和示例,便于学习和解决问题。
- 支持异步测试:可以处理 Promises 和异步函数,适合用于测试小程序中的异步 API。
学习单元测试的方法
我主要通过以下方式学习单元测试:
- 官方文档:阅读 Jest 官方文档 了解基本用法和高级功能。
- 示例项目:查找和分析开源项目中的测试示例,理解最佳实践。
- 在线教程:观看 YouTube 和 Coursera 上的相关教程,结合视频和实践加深理解。
简易教程
以下是一个简易的 Jest 测试教程:
安装 Jest
npm install --save-dev jest
创建测试文件
在项目目录中,创建一个 __tests__
文件夹,并在其中创建测试文件,例如 app.test.js
。
编写测试代码
const app = require('../app.js'); // 导入要测试的模块
test('用户名和密码不能为空', () => {
expect(app.validateCredentials('', '')).toBe(false);
});
运行测试
在命令行中,运行以下命令以执行测试:
npx jest
## 2. 项目部分单元测试代码【3分】
### 测试代码示例
以下是针对注册和登录功能的部分单元测试代码:
```javascript
const app = require('../app.js'); // 假设 app.js 是要测试的模块
describe('User Registration and Login', () => {
test('should not allow empty username and password', () => {
const result = app.submit('', '');
expect(result).toBe('账号密码不能为空');
});
test('should show error if username already exists', async () => {
// 构造测试数据
const existingUser = { user: 'testuser', password: 'testpass' };
await app.models.userInfo.create({ data: existingUser }); // 创建一个用户
const result = await app.submit('testuser', 'newpass');
expect(result).toBe('账号已存在');
});
test('should successfully register a new user', async () => {
const result = await app.submit('newuser', 'newpass');
expect(result).toBe('注册成功');
});
test('should show error for incorrect login', async () => {
const result = await app.submit('wronguser', 'wrongpass');
expect(result).toBe('账号密码不存在');
});
test('should successfully login with correct credentials', async () => {
await app.models.userInfo.create({ data: { user: 'loginuser', password: 'loginpass' } });
const result = await app.submit('loginuser', 'loginpass');
expect(result).toBe('登录成功');
});
});
测试的函数
submit()
: 此函数用于处理用户的注册和登录逻辑,并根据不同的情况返回相应的提示信息。
3. 构造测试数据的思路【3分】
测试数据构造思路
在构造测试数据时,我考虑以下几点:
-
边界情况:确保测试包括空输入、过长的用户名或密码等情况。例如:
- 空用户名和密码。
- 已存在的用户名。
- 不匹配的登录凭据。
-
有效数据:创建有效的用户数据用于测试注册和登录,例如:
- 一个有效的用户名和密码组合。
- 一个只包含字母和数字的用户名。
-
异常情况:模拟可能发生的异常,例如数据库错误、网络问题等,通过 mock 处理这些情况。
考虑将来的测试人员的***难
为了考虑将来的测试人员的***难,我会:
- 保持代码的可扩展性:确保测试代码易于修改和扩展,以适应新需求。
- 编写详细的文档:提供清晰的测试说明和测试数据的背景,让其他人可以快速理解和修改。
- 添加更多的测试用例:针对可能的边界情况和潜在的失败场景添加更多测试用例。
通过这种方式,可以确保我们的单元测试能够应对各种场景,并且为将来的维护和扩展打下良好的基础。
七、Github 的代码签入记录截图
八、问题及解决方法
一、数据内存太多,小程序无法在手机上呈现
- 问题描述:由于数据内存占用过多,导致小程序在手机上运行时出现卡顿甚至无法呈现的情况。其中部分图片数据占用了大量内存空间。
- 解决方法:将部分图片载入数据库,通过优化图片存储方式,减少内存占用。在需要展示图片时,从数据库中动态加载图片,而不是一次性将所有图片加载到内存中。
二、数据库连接异常,无法建立数据库
- 问题描述:在开发过程中,出现数据库连接异常的情况,导致无法成功建立数据库连接。
- 解决方法:确保环境 ID 配置正确,成员协作配置数据库环境。检查数据库配置参数,如数据库地址、端口号、用户名和密码等是否正确。同时,检查网络连接是否正常,确保小程序能够与数据库服务器进行通信。
三、数据不同步(比如发布项目后在项目栏里无法出现新发布的项目)
- 问题描述:数据不同步问题表现为发布项目后,项目栏中无法及时出现新发布的项目,影响用户体验。
- 解决方法:增加刷新功能,用户点击即可刷新项目列表。在发布项目后,通过触发刷新事件,从数据库中重新获取项目数据并更新项目栏的显示。同时,优化数据同步机制,确保新发布的项目能够及时同步到各个客户端。
四、反应速度慢
- 问题描述:小程序反应速度慢,影响用户操作的流畅性和体验。
- 解决方法:优化代码,更换部分函数以及调用云数据库的方法等,提高小程序性能。对代码进行性能分析,找出性能瓶颈并进行优化。例如,优化数据库查询语句,减少不必要的数据库访问;采用缓存技术,提高数据访问速度;优化界面渲染,减少不必要的界面更新等。
九、评价
一、值得学习的地方
(一)专业能力
在技术方面表现出较高的专业水准,对小程序开发涉及的前端和后端技术都有深入的理解。例如,在处理用户认证模块时,能够熟练运用加密算法确保用户密码的安全性,同时通过前后端的紧密配合实现高效的身份验证机制。
(二)团队协作
- 具有良好的团队协作精神,能够积极与其他成员沟通和协作,共同解决项目中遇到的问题。在分工明确的基础上,能够主动承担一些额外的任务,为团队的整体目标贡献自己的力量。
二、需要改进的地方
(一)时间管理
在项目开发过程中,有时会出现时间预估不准确的情况,导致部分任务未能按时完成。在处理一些紧急问题时,可能会因为过于专注于问题的解决而忽略了其他任务的进度。
(二)沟通方式
在与其他成员沟通时,有时会因为表达不够清晰而导致误解。需要进一步提高沟通能力,更加清晰地表达自己的观点和想法,确保信息的准确传递。