软件工程第二次结对作业
软件工程 | https://edu.cnblogs.com/campus/fzu/SE2024 |
---|---|
作业要求 | https://edu.cnblogs.com/campus/fzu/SE2024/homework/13281 |
作业目标 | 基于第一次结对作业项目程序的实现 |
学号 | 102201129 |
合作伙伴 | 102201127 |
项目分工:
102201129周鑫:
前端开发:
设计和实现用户界面。
确保界面响应性和兼容性。
使用[指定技术栈]开发前端功能。
用户体验:
收集用户反馈。
根据反馈优化界面设计。
102201127罗永辉:博客链接
后端开发:
设计和实现服务器逻辑。
管理数据库和数据模型。
使用[指定技术栈]开发API接口。
服务器管理:
部署和维护服务器。
确保服务器的安全性和稳定性。
github仓库链接:https://github.com/Daxinzhou/102201129-102201127
PSP表格
PSP 2.1 Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
Planning | 60 | 70 |
Estimate | 30 | 45 |
Development | 300 | 350 |
Analysis | 90 | 120 |
Design Spec | 45 | 60 |
Design Review | 30 | 40 |
Coding Standard | 20 | 30 |
Design | 60 | 75 |
Coding | 120 | 150 |
Code Review | 45 | 60 |
Test | 60 | 90 |
Reporting | 30 | 45 |
Test Report | 15 | 20 |
Size Measurement | 10 | 15 |
Postmortem & Process Improvement Plan | 45 | 60 |
合计 | 900 | 1100 |
代码实现思路
css文件夹存放项目的css文件。
img文件夹存放项目所使用到的资源图片。
js文件夹存放JavaScript文件。
unpackage文件夹存放未打包资源。
项目目录中的c1文件夹存放项目的后端代码。
在c1文件夹中,middleware是中间件目录,用于处理HTTP请求前后的逻辑;models是数据模型目录,通常包含数据库模型定义;node_modules是Node.js项目的依赖库目录 ;routes是路由目录,用于定义应用的路由规则;app.js是应用的主入口文件;package.json文件是Node.js项目的配置文件,定义项目依赖和脚本;package-lock.json文件是锁定项目依赖版本,确保安装的依赖一致;server.js文件是服务器的主启动文件。
其余文件是html页面文件。
关键流程图
关键代码解释
document.addEventListener('DOMContentLoaded', function() {
const projectsTab = document.getElementById('projects-tab');
const chatTab = document.getElementById('chat-tab');
const personalTab = document.getElementById('personal-tab');
const projectsPage = document.getElementById('projects-page');
const chatPage = document.getElementById('chat-page');
const personalPage = document.getElementById('personal-page');
const chatFrame = document.getElementById('chat-frame');
const startProjectBtn = document.getElementById('start-project-btn');
projectsTab.addEventListener('click', function() {
showPage(projectsPage);
});
chatTab.addEventListener('click', function() {
showPage(chatPage);
// Ensure the chat page is loaded when accessing the chat tab
chatFrame.src = "chat.html";
});
personalTab.addEventListener('click', function() {
showPage(personalPage);
});
startProjectBtn.addEventListener('click', function() {
// 跳转到发起项目的页面
window.location.href = 'start-project.html';
});
function showPage(page) {
const pages = [projectsPage, chatPage, personalPage];
pages.forEach(function(p) {
p.classList.remove('active');
});
page.classList.add('active');
document.querySelectorAll('.tab-button').forEach(function(btn) {
btn.classList.remove('active');
});
const activeTab = document.querySelector('.tab-button#' + page.id + '-tab');
if (activeTab) {
activeTab.classList.add('active');
}
}
// Set the default active page
showPage(projectsPage); // Assuming the default active page is the projects page
});
这段代码是一个JavaScript脚本,它通过监听文档加载完成事件来初始化页面上的标签切换功能。首先,它获取了页面上各个标签和对应页面的DOM元素。然后,为每个标签设置点击事件监听器,当点击时,会触发showPage函数,该函数负责隐藏所有页面,显示当前被点击的页面,并更新标签的激活状态。对于聊天标签,点击时还会确保聊天页面的内容被加载。此外,还有一个按钮用于跳转到创建项目的页面。最后,脚本设置了默认显示的项目页面。整个脚本实现了一个标签页切换的效果,允许用户通过点击不同的标签来切换显示不同的页面内容,同时保持标签的激活状态与显示的页面同步。
设计创意独到之处
可以在首页发起项目中邀请老师指导项目开发且可供选择的老师很多,意义就是老师们与学生们的联系可以更快速的建立
实现思路
在项目发起中根据项目专业需求选择老师以及所需要合作同学的专业
代码片段
document.addEventListener('DOMContentLoaded', function() {
const backToProjectBtn = document.getElementById('back-to-project-btn');
backToProjectBtn.addEventListener('click', function() {
// 返回到发起项目的页面
window.location.href = 'start-project.html';
});
// 为每个导师项添加点击事件,假设选择后返回项目并带有选择的导师信息
document.querySelectorAll('.mentor-item').forEach(function(mentor) {
mentor.addEventListener('click', function() {
const mentorName = this.textContent.split(' - ')[0]; // 假设文本格式为 "导师名 - 专业领域"
// 可以将选择的导师信息保存到localStorage或通过URL传递
localStorage.setItem('selectedMentor', mentorName);
window.location.href = 'start-project.html';
});
});
});
成果展示
目录说明
css文件夹存放项目的css文件。
img文件夹存放项目所使用到的资源图片。
js文件夹存放JavaScript文件。
unpackage文件夹存放未打包资源。
项目目录中的c1文件夹存放项目的后端代码。
在c1文件夹中,middleware是中间件目录,用于处理HTTP请求前后的逻辑;models是数据模型目录,通常包含数据库模型定义;node_modules是Node.js项目的依赖库目录 ;routes是路由目录,用于定义应用的路由规则;app.js是应用的主入口文件;package.json文件是Node.js项目的配置文件,定义项目依赖和脚本;package-lock.json文件是锁定项目依赖版本,确保安装的依赖一致;server.js文件是服务器的主启动文件。
其余文件是html页面文件。
使用说明
安装项目文件后,点击桌面的大学生项目匹配app,进入app.
首先选择老师或者学生进入相应登录页面,输入自己的信息即可进入主页面。
进入主页面后,可以看到最下面有导航栏,分别是项目,聊天,个人。
打开项目页面即主界面后,用户可以浏览网页信息,学习一些自己感兴趣的课程。点击右上角的发起项目按钮即可进入发起项目界面。在这个界面使用者可以填写自己要发起的项目的有关信息,并且可以邀请自己心仪的导师。
打开聊天界面后,使用者可以与伙伴或导师进行交流。
打开个人界面后,使用者可以编辑自己的个人信息并保存。
单元测试
选用Jest单元测试
如何学习
理解单元测试的基本概念,选择合适的测试框架,根据你使用的编程语言和开发环境选择合适的测试框架,
学习测试框架的文档,阅读官方文档,了解如何设置测试环境,编写测试用例,以及运行测试。
编写测试用例,学习如何编写测试用例,包括设置测试环境、执行测试和验证结果。
在实际项目中应用单元测试,从简单的功能开始,逐步扩展到更复杂的场景。
学习测试驱动开发,了解测试驱动开发的概念,这是一种先编写测试用例,再编写代码的开发方法。
加入社区,参与讨论,学习他人的经验和最佳实践。
测试代码
const chatRooms = {};
test('sends a message to a room', () => {
const roomId = 'room1';
const testMessage = 'Hello, World!';
sendMessage(roomId, testMessage);
expect(chatRooms[roomId]).toHaveLength(1);
expect(chatRooms[roomId][0].message).toBe(testMessage);
});
test('stores messages with a timestamp', () => {
const roomId = 'room2';
const testMessage = 'This is a test message';
sendMessage(roomId, testMessage);
const messageTimestamp = chatRooms[roomId][0].timestamp;
expect(messageTimestamp).toBeGreaterThan(Date.now() - 1000); // 检查时间戳是否在1秒以内
});
test('adds message to existing room', () => {
const roomId = 'room3';
sendMessage(roomId, 'First message');
sendMessage(roomId, 'Second message');
expect(chatRooms[roomId]).toHaveLength(2);
});
test('creates new room if not exists', () => {
const roomId = 'room4';
sendMessage(roomId, 'New room message');
expect(chatRooms[roomId]).toBeDefined();
expect(chatRooms[roomId]).toHaveLength(1);
});
这些测试用例覆盖了sendMessage函数的不同情况
第一个测试用例检查消息是否被添加到指定的聊天室。
第二个测试用例检查消息是否带有时间戳。
第三个测试用例检查向已存在的聊天室添加消息。
第四个测试用例检查当聊天室不存在时,是否创建新的聊天室。
构造测试数据的思路
在设计测试数据时,我们需要确保覆盖所有可能的使用场景,包括正常情况、边界条件、异常情况等。正常情况指的是日常使用中最常见的操作,比如发送一条普通的消息。边界条件可能涉及到消息长度的限制、特殊字符的处理等。异常情况则是指非预期的输入,比如空消息、非法字符等。此外,我们还需要考虑数据的多样性,比如不同长度的消息、不同类型(如文本、图片、视频)的消息,以及不同时间戳的消息。通过这样的测试数据构造,我们可以确保函数在各种情况下都能正确处理,从而提高代码的健壮性和可靠性。
应对测试人员的***难
测试人员可能会从不同的角度对功能进行挑战,以确保代码的健壮性。例如,他们可能会测试在高并发环境下,消息是否能正确无误地发送和接收,这涉及到消息的顺序和完整性。此外,他们还可能测试在极端情况下,比如网络延迟、服务中断等情况下,系统的响应和恢复能力。为了应对这些挑战,我们需要在设计测试时就考虑到这些极端情况,并确保我们的代码能够优雅地处理这些情况。同时,我们还需要考虑代码的可维护性和可扩展性,以便在未来添加新功能或修改现有功能时,能够快速适应变化,保持系统的稳定性。通过这样的前瞻性测试,我们可以确保我们的应用在面对未来可能的挑战时,依然能够保持高效和稳定。
Github签入
困难以及解决办法
遇到的困难
DOM元素获取问题:如果HTML和JavaScript之间的ID不匹配或脚本在DOM元素加载前执行,可能导致无法正确获取元素。
动态内容处理:动态加载的内容可能在脚本执行时尚未存在,影响事件监听器的绑定和功能实现。
跨浏览器兼容性:不同浏览器对JavaScript和CSS的支持差异可能导致脚本在某些浏览器上无法正常工作。
维护和扩展性:随着项目规模的扩大,添加更多功能时,代码的组织和维护可能变得复杂。
性能优化:在存在大量DOM操作的情况下,性能可能受到影响,尤其是在低端设备或老旧浏览器上。
可采取的措施
确保DOM元素正确获取:通过确保ID的一致性和在DOM完全加载后执行脚本来避免获取元素时的错误。
处理动态内容:使用事件委托或确保在内容加载完成后再绑定事件监听器,以适应动态内容的变化。
增强跨浏览器兼容性:采用广泛支持的API和属性,并使用Polyfills来兼容旧浏览器,同时进行跨浏览器测试。
提高代码的可维护性和扩展性:通过模块化和使用现代前端框架来组织代码,简化功能的添加和管理。
优化性能:减少DOM操作,使用文档片段或虚拟DOM技术,以及利用CSS类切换来提升性能。
评价队友
在APP开发合作的整个过程中,我的结对同学展现出了良好的专业能力和务实的工作态度。他熟练掌握了多种编程语言和开发工具,遇到技术难题时,总是能够冷静分析并提出切实可行的解决方案。我们之间的合作非常顺畅,能够就项目细节进行充分讨论并达成共识,共同推动了项目的稳步前进,确保了项目的顺利进行和按时交付。
改进之处
尽管我的搭档表现非常优秀,但在项目管理上还有进一步提升的空间。例如,在任务分配和时间规划方面可以更加细致,确保每个阶段的工作都能高效有序地推进。此外,面对突发问题时,如果能更加冷静快速地做出决策,将有助于我们更好地应对挑战,提高整体工作效率。不过,这些都是一些小的建议,并不影响他对这次项目做出的巨大贡献。