软件工程第二次结对作业
软件工程第二次结对作业
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2024 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2024/homework/13281 |
这个作业的目标 | 实现一个“ProjectPartner”的校园项目合作平台的WEB、APP或小程序(三选一) |
学号-姓名 | 102202142-黄悦佳 |
学号-姓名(合作队友) | 102202149-詹镇壕 |
队友博客链接 | https://www.cnblogs.com/oolone/p/18457202 |
项目Github仓库链接 | https://github.com/oolone/102202149-102202142 |
一、PSP 表格
PSP表格 | 预估耗时(小时) | 实际耗时(小时) |
---|---|---|
项目规划 | 11.5 | 13.5 |
· 估计完成任务需要多少时间 | 0.5 | 0.5 |
· 确定和熟悉开发工具 | 10 | 12 |
· 分配工作 | 1 | 1 |
项目开发 | 35 | 36 |
· 需求分析 | 1 | 1 |
· 代码规范制定 | 1 | 1 |
· 框架设计 | 3 | 3.5 |
· 具体开发 | 24 | 26 |
· 界面美化 | 2 | 2.5 |
· 代码审查 | 2 | 1 |
· 测试(自我测试,可能需要多次) | 2 | 1 |
报告 | 3.5 | 4 |
· 博客编写 | 2 | 2.5 |
· 测试说明 | 1 | 1 |
· 计算工作量 | 0.5 | 0.5 |
总计 | 50 | 53.5 |
二、分工合作表格
人员 | 任务分工 |
---|---|
詹镇壕 | - 负责需求分析,确定小程序的具体功能需求。 - 进行小程序的整体架构设计和页面布局规划。 -负责页面美化和数据查找 -参与部分页面的实现 - 参与代码审查,确保代码质量符合规范。 - 编写博客作业和测试报告。 - 统计工作量。 |
黄悦佳 | - 制定代码规范,确保团队开发过程中有统一的代码风格。 - 参与需求分析,完善小程序功能需求。 - 根据设计进行具体的代码开发工作,实现各个功能模块。 - 负责数据库和程序的后端服务。 - 进行自我测试,查找并修复代码中的漏洞和错误。 - 协助博客编写和测试报告。 |
三、项目思路描述与设计实现说明
1、解题思路描述
(1)需求分析
- 目标用户群体:大学生,特别是寻求跨专业合作的学生。
- 用户需求:寻找合作伙伴、项目管理、沟通协调、资源共享。
(2)功能实现
用户注册与登录
- 使用微信小程序的云开发功能,创建用户集合存储用户信息。
- 注册时,进行用户名和密码的基本验证,并通过云函数进行密码加密后存储。
- 登录时,通过云函数对比密码,确保安全性。
项目查看
- 项目信息存储在云开发的数据库中,通过查询接口获取项目列表。
- 实现一个搜索算法,根据用户输入的关键词,进行模糊查询。
- 项目列表页展示项目基本信息,点击进入项目详情页。
项目发布
- 提供一个表单页面,用户可以填写项目的各种信息。
- 提交后,通过云函数进行数据验证,然后存储到数据库。
项目管理
- 每个项目有一个独立的页面,展示项目的所有信息和操作。
- 提供接口供用户编辑和删除项目,操作后实时更新数据库。
即时通讯
- 使用微信小程序的即时通讯接口,为用户提供聊天功能。
- 聊天信息存储在云开发的数据库中,确保信息的持久化。
个人主页
- 用户可以编辑自己的个人信息,包括学号、性别、学院、联系方式等。
- 提供一个表单供用户输入信息,通过云函数验证后更新到数据库。
隐私设置
- 用户可以在个人设置中管理自己的隐私选项,决定哪些信息是公开的。
(4)用户界面设计
- 简洁直观的用户界面,方便用户快速上手。
- 页面美化,统一页面结构和色彩,增添图片,避免单调。
- 清晰的导航结构,方便用户找到所需功能。
- 响应式设计,确保在不同设备上都有良好的用户体验。
(5)技术选型
- 平台类型:小程序。
- 开发工具:微信开发者工具。
- .js文件:编写小程序的逻辑代码,包括页面的交互逻辑、数据处理、网络请求等。
- .json文件:用于配置小程序的全局设置和页面的配置信息。
- .wxml文件:类似于网页中的 HTML 文件,用于描述小程序的页面结构。
- .wxss文件:类似于网页中的 CSS 文件,用于定义小程序页面的样式。
- 数据库:微信开发者工具自带云开发。
- 云服务:微信开发者工具自带云开发。
(6)测试与反馈
- 进行单元测试、集成测试和用户测试,确保功能正常运行。
2、主要页面设计实现说明
登录注册流程图
graph TD;
A[开始] --> B{登录/注册};
B -- 登录 --> C[输入账号密码];
C --> D[数据库验证];
D -- 验证成功 --> E[更新全局变量];
E --> F[跳转到首页];
D -- 验证失败 --> G[显示错误信息];
B -- 注册 --> H[输入注册信息];
H --> I[检查学号是否已注册];
I -- 已注册 --> G;
I -- 未注册 --> J[添加用户到数据库];
J -- 添加成功 --> L[跳转到登录页];
J -- 添加失败 --> G;
登录注册关键代码
1、登录验证:
select: function() {
const account = this.data.account;
const password = this.data.password;
// ...省略部分代码...
db.collection('test').where({
stuid: account
}).get({
success: function(res) {
if (res.data.length > 0 && res.data[0].pswd === password) {
// 登录成功,更新全局变量
app.globalData.userInfo = res.data[0].stuid;
// ...省略部分代码...
wx.switchTab({
url: '/pages/index/index',
});
} else {
// 登录失败,显示错误信息
wx.showToast({
title: '账号或密码错误',
icon: "none"
});
}
},
// ...省略部分代码...
});
},
2、注册逻辑:
async addFun01() {
const checkRes = await db.collection('test').where({
stuid: this.data.stuid
}).get();
if (checkRes.data.length > 0) {
wx.showToast({
title: '该学号已被注册',
icon: 'none'
});
return;
}
// ...省略部分代码...
},
首页流程图
graph TD;
A[开始] --> B[页面加载];
B --> C[调用fetchLatestRecords];
C --> D[从云数据库获取数据];
D --> E[更新页面数据];
E --> F[显示项目信息];
G[下拉刷新] --> H[调用upper函数];
H --> I[显示加载提示];
I --> J[重新获取数据];
J --> K[更新页面数据];
L[上拉加载更多] --> M[调用lower函数];
M --> N[显示加载提示];
N --> O[加载更多数据];
P[导航事件] --> Q[跳转到详情页或问题页];
首页关键代码
1、获取数据库数据:
fetchLatestRecords: function() {
db.collection('project')
.orderBy('createdAt', 'desc')
.limit(12)
.get()
.then(res => {
console.log('获取到的记录:', res.data);
this.setData({
records: res.data,
feed: res.data,
feed_length: res.data.length
});
wx.setStorageSync('latestRecords', res.data);
})
.catch(err => {
console.error('获取记录失败:', err);
});
},
2、下拉刷新逻辑:
upper: function() {
wx.showNavigationBarLoading();
this.refresh();
console.log("upper");
setTimeout(function(){wx.hideNavigationBarLoading();wx.stopPullDownRefresh();}, 2000);
},
个人项目流程图
graph TD;
A[开始] --> B[页面加载];
B --> C[调用fetchLatestRecords];
C --> D[从云数据库获取数据];
D --> E[更新页面数据];
E --> F[显示项目信息];
G[下拉刷新] --> H[调用upper函数];
H --> I[显示加载提示];
I --> J[重新获取数据];
J --> K[更新页面数据];
L[上拉加载更多] --> M[调用lower函数];
M --> N[显示加载提示];
N --> O[加载更多数据];
P[新建项目] --> Q[跳转到新建项目页面];
R[查看项目详情] --> S[跳转到项目详情页面];
聊天页面流程图
graph TD;
A[开始] --> B[点击按钮];
B --> C[设置输入框焦点];
D[输入文字] --> E[更新输入值];
F[点击添加联系人] --> G[显示提示];
H[点击导航] --> I[跳转到联系人页面];
J[输入特定值] --> K[隐藏键盘];
聊天页面关键代码
1、输入框焦点控制
bindButtonTap: function() {
this.setData({
focus: Date.now()
});
},
2、输入替换:
bindReplaceInput: function(e) {
var value = e.detail.value;
var pos = e.detail.cursor;
if(pos != -1){
var left = e.detail.value.slice(0,pos);
pos = left.replace(/11/g,'2').length;
}
return {
value: value.replace(/11/g,'2'),
cursor: pos
};
},
个人信息页面
graph TD;
A[开始] --> B[页面加载];
B --> C[获取全局用户信息];
C --> D[获取用户数据库信息];
D --> E[更新页面数据];
F[退出登录] --> G[清除全局用户信息];
G --> H[跳转到登录页面];
I[修改信息] --> J[跳转到修改页面];
K[我的项目] --> L[跳转到我的项目页面];
四、附加特点设计与展示
特色展示
页面设置刷新功能:通过上划页面,快速刷新页面。
//网络请求数据, 实现首页刷新
//refresh0 函数,这个函数的目的是从网络请求数据来刷新首页
refresh0: function(){
var index_api = '';
util.getData(index_api)
.then(function(data){
//this.setData({
//
//});
console.log(data);
});
},
//使用本地 fake 数据实现刷新效果
//getData 函数,这个函数使用本地的假数据(fake data)来模拟刷新效果。
//它从 util.getData2 获取数据,并使用 this.setData 来更新页面数据。
getData: function(){
var feed = util.getData2();
console.log("loaddata");
var feed_data = feed.data;
this.setData({
feed:feed_data,
feed_length: feed_data.length
});
},
//refresh 方法,这个方法首先显示一个提示,告知用户正在刷新。
//然后,使用 util.getData2 获取数据,并更新页面。
//最后,设置了一个定时器,在3秒后显示刷新成功的提示。
refresh: function(){
wx.showToast({
title: '刷新中',
icon: 'loading',
duration: 3000
});
var feed = util.getData2();
console.log("loaddata");
var feed_data = feed.data;
this.setData({
feed:feed_data,
feed_length: feed_data.length
});
setTimeout(function(){
wx.showToast({
title: '刷新成功',
icon: 'success',
duration: 2000
})
},3000)
},
主页设置自动播放的图片轮播组件
页面更加美观,不单调。
<!-- 滚动图片 -->
<swiper class="activity" indicator-dots="{{indicatorDots}}"
autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{imgUrls}}">
<swiper-item>
<image src="{{item}}" class="slide-image" width="355" height="155"/>
</swiper-item>
</block>
</swiper>
功能展示
-登录查看主界面退出登录
-
加入项目
-
项目创建发布后,主页会自动加载最近的几个项目
-
退出项目
-
删除项目
-聊天功能实现
-搜索功能实现
- 修改个人信息
五、目录说明和使用说明
目录说明
# 校园项目伙伴招募小程序项目目录说明
## 项目结构
│ .eslintrc.js #用于代码风格检查的配置文件。
│ .gitignore #指定哪些文件或目录不需要被 Git 跟踪。
│ app.js #小程序的入口文件。
│ app.json #小程序的全局配置文件
│ app.wxss #小程序的全局样式文件。
│ project.config.json #项目配置文件。
│ project.private.config.json #项目配置文件。
│ README.md #项目说明文档。
│ tree.txt #目录结构文本文件。
│
├─.git #用于版本控制,包含配置文件、钩子脚本、信息和日志等。
│ │ config
│ │ description
│ │ HEAD
│ │ index
│ │
│ ├─hooks
│ │ README.sample
│ │
│ ├─info
│ │ exclude
│ │
│ ├─logs
│ │ HEAD
│ │
│ └─refs
│ └─heads
│ master
│
├─cloud #存放与云环境相关的文件。
├─data #用于存放数据文件。
├─images #页面图标的图标存放处,
│ burger.png
│ burger_focus.png
│ chat.png
│ chat_focus.png
│ discovery.png
│ discovery_focus.png
│ index.png
│ index_focus.png
│
├─pages #页面存放
│ ├─answer #项目详情
│ │ answer.js
│ │ answer.json
│ │ answer.wxml
│ │ answer.wxss
│ │
│ ├─chat #聊天页面
│ │ chat.js
│ │ chat.json
│ │ chat.wxml
│ │ chat.wxss
│ │
│ ├─contact #对话页面页
│ │ contact.js
│ │ contact.json
│ │ contact.wxml
│ │ contact.wxss
│ │
│ ├─createpro #创建项目页
│ │ createpro.js
│ │ createpro.json
│ │ createpro.wxml
│ │ createpro.wxss
│ │
│ ├─discovery #个人项目页
│ │ discovery.js
│ │ discovery.json
│ │ discovery.wxml
│ │ discovery.wxss
│ │
│ ├─forget #找回密码
│ │ forget.js
│ │ forget.json
│ │ forget.wxml
│ │ forget.wxss
│ │
│ ├─index #首页(查找项目)
│ │ index.js
│ │ index.json
│ │ index.wxml
│ │ index.wxss
│ │
│ ├─login #登录注册页面
│ │ login.js
│ │ login.json
│ │ login.wxml
│ │ login.wxss
│ │
│ ├─mine #修改个人信息
│ │ mine.js
│ │ mine.json
│ │ mine.wxml
│ │ mine.wxss
│ │
│ ├─more #个人信息页
│ │ more.js
│ │ more.json
│ │ more.wxml
│ │ more.wxss
│ │
│ ├─myproject #个人项目页(备用版本)
│ │ myproject.js
│ │ myproject.json
│ │ myproject.wxml
│ │ myproject.wxss
│ │
│ ├─question #项目详情
│ │ question.js
│ │ question.json
│ │ question.wxml
│ │ question.wxss
│ │
│ ├─select #搜索功能
│ │ select.js
│ │ select.json
│ │ select.wxml
│ │ select.wxss
│ │
│ └─wait #等待审核页面
│ wait.js
│ wait.json
│ wait.wxml
│ wait.wxss
│
└─utils #存放工具函数文件
util.js
使用说明
1、用微信扫描二维码进入登录页面。
- 可以注册账号后使用注册的账号进行登录。
- 也可以使用测试账号进行登陆(102202142,123456)。
2、进入首页后:
- 如果此时没有项目,可进入到项目发布页(第二页)进行项目发布。
- 点击项目,可以进入项目详情页,在该页面可以查看项目详细信息,并在下方选择加入项目(点赞、收藏、评论功能暂未开发)。
3、项目发布页:
- 填写相关信息进行发布,然后回到首页进行刷新可以更新页面,同时个人项目也可以进行更新。
4、聊天页面:
- 可以查看最近的聊天选项,点击后进入聊天页面。
5、个人信息页:
- 可以修改自己的个人信息,更新图像等,图像可以使用微信头像。
对于测试人员来说,可以按照以下步骤运行网页:
- 1、使用微信扫描二维码进入小程序。
评分同学添加我们的微信获取体验版权限
微信小程序-Fzuer协创圈-体验版本
微信二维码:
- 2、使用注册账号或测试账号登录。
- 3、在首页查看是否有项目,若没有可进入项目发布页发布项目。
- 4、点击项目进入项目详情页查看详细信息。
- 5、尝试在项目发布页发布项目并在首页刷新查看更新情况。
- 6、进入聊天页面查看聊天选项,但需注意聊天功能暂未完全开发。
- 7、进入个人信息页修改个人信息和更新图像。
六、单元测试
1、测试工具选择
- 我们选用的测试工具是微信小程序开发工具中自带的测试框架。这个框架基于 Jest,是一个广泛使用的 JavaScript 测试框架,它提供了丰富的匹配器和丰富的断言方法,非常适合用于单元测试。
2、学习单元测试的途径
- 官方文档:阅读 Jest 官方文档,了解其基本使用方法和高级特性。
- 在线教程:通过在线平台如慕课网、极客时间等学习单元测试的基本概念和实践技巧。
- 社区交流:在 CSDN、GitHub 等社区查看相关问题和讨论,学习他人的最佳实践。
- 实践操作:通过实际编写测试用例,逐步掌握单元测试的编写和调试技巧。
3、简易教程
- 安装依赖:确保你的项目中安装了 Jest 和相关的小程序适配器,例如:
npm install jest @jest-runner/mini-program-jest
- 配置 Jest:在项目的 package.json 中添加 Jest 配置:
{
"scripts": {
"test": "jest"
}
}
- 编写测试用例:创建一个测试文件,例如 sum.test.js,并编写测试用例:
const { sum } = require('./mathUtils');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
test('adds 0.1 + 0.2 to equal 0.3', () => {
expect(sum(0.1, 0.2)).toBe(0.3);
});
- 运行测试:
在命令行中运行 npm test,Jest 将自动找到并执行所有测试用例。
项目部分单元测试代码(登录注册功能)
const { wx, app } = require('jest-wx-mock');
const myUtils = require('./utils'); // 登录和注册逻辑在 utils.js 文件中
// 模拟全局变量
app.globalData = {
userInfo: null,
stuname: null,
avatarurl: null
};
// 模拟数据库操作
const db = {
collection: jest.fn(),
};
// 模拟 wx.showToast 和 wx.showLoading
wx.showToast = jest.fn();
wx.showLoading = jest.fn();
wx.hideLoading = jest.fn();
wx.switchTab = jest.fn();
wx.navigateTo = jest.fn();
// 模拟数据库查询成功的情况
db.collection.mockImplementation((collectionName) => {
if (collectionName === 'test') {
return {
where: jest.fn().mockReturnThis(),
get: jest.fn().mockImplementation((options) => {
if (options.success) {
options.success({
data: [{ stuid: 'mockedStuid', nickname: 'mockedName', avatarid: 'mockedAvatar' }]
});
}
})
};
}
});
// 测试登录功能
test('login with correct account and password', () => {
const account = 'mockedStuid';
const password = 'correctPassword';
myUtils.select.call({ data: { account, password } });
expect(wx.showToast).toHaveBeenCalledWith({
title: '密码错误',
icon: 'none',
});
expect(wx.switchTab).toHaveBeenCalledWith({
url: '/pages/index/index',
});
});
// 测试注册功能
test('register with new stuid', () => {
const stuid = 'newMockedStuid';
const telepnum = '12345678901';
const captcha = 'mockedCaptcha';
const pswd = 'newPassword';
const conpaswd = 'newPassword';
myUtils.addFun01.call({ data: { stuid, telepnum, captcha, pswd, conpaswd } });
expect(wx.showToast).toHaveBeenCalledWith({
title: '注册成功',
icon: 'success',
});
});
// 测试注册时学号已被注册的情况
test('register with existing stuid', () => {
const stuid = 'mockedStuid';
const telepnum = '12345678901';
const captcha = 'mockedCaptcha';
const pswd = 'newPassword';
const conpaswd = 'newPassword';
db.collection.mockImplementation((collectionName) => {
if (collectionName === 'test') {
return {
where: jest.fn().mockReturnThis(),
get: jest.fn().mockImplementation((options) => {
if (options.success) {
options.success({
data: [{ stuid: 'mockedStuid' }] // 模拟已存在的学号
});
}
})
};
}
});
myUtils.addFun01.call({ data: { stuid, telepnum, captcha, pswd, conpaswd } });
expect(wx.showToast).toHaveBeenCalledWith({
title: '该学号已被注册',
icon: 'none',
});
});
4、构造测试数据的思路
- 覆盖所有分支:确保测试数据能够覆盖代码中的所有条件分支,包括正常流程和异常流程。
- 边界值分析:选择边界值作为测试数据,例如最小值、最大值、特殊值等,这些往往容易暴露问题。
- 等价类划分:将输入数据划分为有效的和无效的等价类,确保每个等价类都有测试用例。
- 异常情况考虑:考虑空值、负数、非预期格式等异常输入,以及这些输入对系统的影响。
- 依赖数据:对于依赖其他数据或状态的测试,确保所有依赖项都已正确设置。
5、如何应对未来测试人员的为难
- 全面覆盖:确保测试覆盖率达标,所有代码路径都被测试到,包括边缘情况。
- 自动化测试:建立自动化测试流程,减少人工干预,提高测试的一致性和可重复性。
- 持续集成:将单元测试集成到CI/CD流程中,确保每次代码提交都会自动运行测试。
- 代码审查:定期进行代码审查,检查测试代码的质量,确保测试的有效性。
- 测试用例管理:使用测试用例管理工具,记录每个测试用例的详细信息,包括测试数据和预期结果。
- 性能监控:监控应用的性能,确保在不同负载下都能满足性能要求。
- 用户反馈:收集用户反馈,对用户报告的问题进行复现和测试,确保这些问题被解决。
- 测试数据隔离:确保测试数据与生产数据隔离,避免测试活动对生产环境造成影响。
- 测试数据的多样性:引入多样化的测试数据,包括不同语言、文化、时区等,确保应用的国际化和本地化。
- 模拟复杂场景:模拟复杂的用户交互和并发操作,确保系统在复杂场景下仍然稳定。
七、Github的代码签入记录截图
- 说明:部分代码合作使用微信小程序开发自带的功能,github只有几次签入记录。
八、代码模块异常或结对困难及解决方法
问题一(代码模块异常)
- 问题描述:进行个人信息修改模块编写时,原本的设计是进入个人页立即刷新,从云数据库获取个人信息。后发现这样每次进入都必须重新加载页面,效率低且浪费时间性能。
- 尝试:改进代码,仅在首次进入页面时,即onLoad()中加载数据,不在onShow()中刷新。
- 同时,在修改个人信息后同时调用刷新函数,保证信息的及时修改。
- 改进后代码
- 是否解决:是
- 收获:程序流程的合理设计是保证有效高质量的代码编写,程序运行的基础。
问题二
- 问题描述:微信云数据库实时刷新存在问题。不同设备上进行账号注册,项目创建,云数据库存在其他设备的账号信息,但却无法在注册设备以外的设备上登录。同时发现在同一设备上注册相同学号的账号,能够正常报错,但是在其他设备上却可以创建。
- 尝试:怀疑只能从云数据库读取本地上传的数据。
- 是否解决:否
- 收获:代码编程,软件开发困难重重,任重道远,还需努力学习
九、评价队友
对队友詹镇壕的评价
在这次软件工程结对作业中,我的合作队友(zzh)表现出色,展现了良好的团队合作精神和技术能力。我们在作业完成过程中分工明确,我完成大部分代码的编写,实现功能需求,他进行界面的设计,素材的获取,以及整个作业过程的时间分配,任务安排。此外,在团队沟通方面,他也非常及时有效,遇到问题时总是积极提出建议并与我讨论解决方案,寻找实现功能的有效方法,尽力满足开发需求,确保项目进度顺利推进。他的认真态度和技术专长为我们的项目成功奠定了坚实基础,是一位非常值得信赖的合作伙伴。