软件工程第二次结队作业

这个作业属于哪个课程 软件工程 SE2024
这个作业要求在哪里 作业要求链接
作业目标 通过代码程序实现项目招募合作伙伴
姓名 曾庆徽
学号 102201542
结对成员 戴康怡
结对成员学号 102201241
结对同学博客链接 戴康怡的博客
GitHub 项目地址 GitHub 项目

1.项目分工

曾庆徽同学
(1)负责项目框架搭建,提供基础的注册,登录以及聊天的前端模板。
(2)后端数据库集合设计以及部分后端开发。
(3)使用Jest工具编写单元测试。
戴康怡同学
(1)调整项目框架给出具体方案,实现项目广场,项目创建,以及个人中心前端界面开发,修改提供的前端模板,实现各个页面之间交互按钮的设计与实现。
(2)主要后端开发,管理后端数据库存储与更新,调试代码修改bug。
(3)绘制数据结构图与流程图。

2.PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 20
Estimate 估计这个任务需要多少时间 5 5
Development 开发 180 220
Analysis 需求分析 (包括学习新技术) 180 300
Coding Standard 代码规范 (为目前的开发制定合适的规范) 20 5
Design 具体设计 300 480
Coding 具体编码 500 1800
Code Review 代码复审 30 90
Test 测试(自我测试,修改代码,提交修改) 60 120
Size Measurement 计算工作量 15 15
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 30 30
合计 ---- 1350 3085

3.解题思路描述与代码分析

需求分析

在本次项目中,用户不仅需要创建项目,提交项目申请,还要管理已经参与和发布的项目。通过设计一个系统,用户无论是作为项目的发布者还是参与者,都能通过统一的界面进行管理。主要需要实现:

  • 用户的注册和登录:为每个用户进行授权
  • 项目的管理逻辑:如何根据用户身份(发布者或参与者)以及项目详情归类不同的项目。
  • 申请加入项目的处理:如何合理地设计项目申请与同意申请之间的反馈。
  • 项目的搜索:如何添加搜索方便用户查找相关项目。
  • 实时聊天功能的实现:不同用户之间如何进行实时的聊天交流,提高沟通效率。

求解思路

基于上述分析,我们设计一个微信小程序来实现,小程序主要有以下功能模块:

  • 微信授权绑定用户:注册时跳转至微信授权方便绑定信息。
  • 项目广场模块:展示所有已经发布的项目,方便用户查看不同项目的标题和内容以及项目创建者的昵称。
  • 项目创建模块:创建个人项目,包含填写项目标题以及。
  • 项目详情模块:显示项目的详细信息,包括项目的名称、内容、进度、开始日期等。参与者可以发起申请,参与项目。
  • 组队申请模块:用于管理组队请求的发送和审核。发布者可以审核组队申请,参与者可以查看自己发出的组队请求状态。
  • 实时聊天模块:用户之间可以实时聊天沟通。
  • 个人中心模块:展示已经创建的项目以及个人头像与昵称,个人昵称与头像进行修改。

数据库图:

结构图:

一些界面截图:


2.

3.

4.

有价值的代码:

// applyDetail.ts
Page({
    data: {
      application: {
        reason: '',
        
        contact: '',
       
        account_id: '',
  project_id:''
      },
  project:{}
    },
  
    onLoad(options: any) {
      const { reason, contact, account_id ,project_id} = options;
      this.setData({
        'application.reason': reason ,
        'application.contact': contact ,
        'application.account_id': account_id ,
  'application.project_id': project_id
      });
  console.log('列表:', this.data.application);
    },
  
    applyForProject() {
        wx.showToast({
      icon: 'none',
      title: '已同意',
    })  
    const db = wx.cloud.database();
    
    const projectId= String(this.data.application.project_id); // 替换为实际项目的 ID
    console.log('申请列表:', this.data.application);
    const newMemberAccountId = String(this.data.application.account_id); // 要添加的成员 account_id

    db.collection('projects').doc(projectId).get()
  .then(res => {
    console.log("项目数据:", res.data);
  })
  .catch(err => {
    console.error("获取项目数据失败:", err);
  });

  
    console.log("Updating project with ID:", projectId);
    console.log("Adding member ID:", newMemberAccountId);

    db.collection('projects').doc(projectId).update({
      data: {
        members: db.command.addToSet(newMemberAccountId) // 使用 addToSet 避免重复
        
      }
    
    }).then(res => {
      console.log("成员添加成功", res);

      wx.showToast({
        title: '成员添加成功',
        icon: 'success'
      });
      
    }).catch(err => {
      console.error("添加成员失败", err);
      wx.showToast({
        title: '添加成员失败',
        icon: 'none'
      });
    });
    
    },
  
  });

这部分是有关申请详情的代码,申请详情将会存在我们的数据库集合applications中,同是也包含了同意申请后成员的添加,包含许多调用变量,几乎将代码里所有用到的变量都调用进去了,也十分考验小程序编写的基本功,总而言之,这部分是最复杂的,我的搭档一个人完成了这个模块,值得点赞。

4.附加特点设计与展示:

独到之处!!:

(1)在项目广场查看项目详情时,项目详情里可以为项目点赞并看到点赞数,一般来说点赞数最高的项目一般也能提现项目的火热度,想到一个冷冰冰的界面需要加上一点闪耀之处让大家感到大大的认可度,我们的点赞符号设计的也十分有新意。

(2)在项目广场加入一个搜索栏,根据搜索的项目标题名称会显示出名称相匹配的项目。
(3)在个人中心中我们用户的昵称还有头像可以自行修改,修改后自动更新新的用户头像和昵称。

实现思路:

  • 对于点赞数我们需要绑定一个点赞数变量跟随其他内容一起加入projects(项目)的数组里,并与点赞按钮互相绑定,当用户点赞时更新点赞数并保存进入projects(方案)数组。
  • 对于搜索功能,我们需要创建一个搜索栏,支持输入项目标题。然后设计一个字符匹配函数,筛选项目标题相同。
  • 对于昵称和头像的改动,昵称设置修改函数并将其保存,头像调用微信支持的的从手机相片里获取的API功能来实现。

有价值代码片段:

选用的还是设置点赞数有关的代码

// projectDetail.ts
Page({
  data: {
      project: {
          title: '',
          nickname: '',
          description: '',
          likecount: 0,
          _id: '',
          members: []  // 新增字段用于存储项目成员
      }
  },

  onLoad(options: any) {
      const { title, nickname, description, likecount, _id } = options;
      console.log('传入的项目 ID:', _id); // 检查传入的 ID
      
      this.setData({
          'project.title': title || '项目名称',
          'project.nickname': nickname || '项目负责人昵称',
          'project.description': description || '项目描述',
          'project.likecount': Number(likecount) || 0,
          'project._id': _id || '' // 确保 ID 被正确设置
      });

      // 获取项目成员
      this.getProjectMembers(_id);
  },

  getProjectMembers(projectId:any) {
      const db = wx.cloud.database();
      db.collection('projects').doc(projectId).get().then(res => {
          // 更新项目的成员数据
          this.setData({
              'project.members': res.data.members || [] // 获取成员数组
          });
          console.log("项目成员:", res.data.members);
      }).catch(err => {
          console.error("获取项目成员失败", err);
      });
  },

  // 点赞按钮的点击事件处理函数
  increaseLikeCount: function() {
      const newLikeCount = this.data.project.likecount + 1;

      // 更新本地点赞数
      this.setData({
          'project.likecount': newLikeCount
      });

      // 直接更新数据库中的点赞数
      const db = wx.cloud.database();
      db.collection('projects').doc(this.data.project._id).update({
          data: {
              likecount: newLikeCount
          },
          success: (res) => {
              console.log('点赞数更新成功', res);
          },
          fail: (err) => {
              console.error('点赞数更新失败', err);
          }
      });
  },

  applyForProject() {
      const projectId = this.data.project._id; // 获取项目的 _id
      wx.navigateTo({
          url: `/pages/apply/apply?id=${projectId}` // 将 _id 作为参数传递
      });
  },

  goToChat() {
      
      wx.switchTab({
          url: `/pages/friends/friends` // 将 _id 作为参数传递
      });
  }
});

理由是在这里是第一次添加点赞数到了我们的代码里,同时这段代码也包含了很多复杂的函数,包括获取项目成员,更新点赞数等,结构清晰,功能完善。

实现结果展示:

5.目录说明和使用说明:

目录结构:

miniprogram/
├── app.js                # 全局逻辑文件,定义应用的生命周期回调函数
├── app.json              # 全局配置文件,配置小程序的页面路径、窗口表现等
├── app.wxss              # 全局样式文件,定义全局样式
├── sitemap.json          # 网站地图文件,用于搜索引擎爬取的配置
├── pages/                # 小程序页面目录
│   ├── index/            # 首页目录
│   │   ├── index.js      # 首页逻辑文件
│   │   ├── index.json    # 首页配置文件
│   │   ├── index.wxml    # 首页的页面结构文件
│   │   └── index.wxss    # 首页的样式文件
│   ├── about/            # 关于页面
│   │   ├── about.js      # 关于页面逻辑文件
│   │   ├── about.json    # 关于页面配置文件
│   │   ├── about.wxml    # 关于页面结构文件
│   │   └── about.wxss    # 关于页面样式文件
│   ├── apply/            # 申请页面
│   │   ├── apply.js      # 申请页面逻辑文件
│   │   ├── apply.json    # 申请页面配置文件
│   │   ├── apply.wxml    # 申请页面结构文件
│   │   └── apply.wxss    # 申请页面样式文件
│   ├── applydetail/      # 申请详情页面
│   │   ├── applydetail.js    #申请详情逻辑文件
│   │   ├── applydetail.json  #申请详情配置文件
│   │   ├── applydetail.wxml  #申请详情结构文件
│   │   └── applydetail.wxss  #申请详情样式文件
│   ├── chat/             # 聊天页面
│   │   ├── chat.js       # 聊天页面逻辑文件
│   │   ├── chat.json     # 聊天页面配置文件
│   │   ├── chat.wxml     # 聊天页面结构文件
│   │   └── chat.wxss     # 聊天页面样式文件
│   ├── create/           # 创建项目页面
│   │   ├── create.js     # 创建项目页面逻辑文件
│   │   ├── create.json   # 创建项目页面配置文件
│   │   ├── create.wxml   # 创建项目页面结构文件
│   │   └── create.wxss   # 创建项目页面样式文件
│   ├── friends/          # 好友页面
│   │   ├── friends.js    # 好友页面逻辑文件
│   │   ├── friends.json  # 好友页面配置文件
│   │   ├── friends.wxml  # 好友页面结构文件
│   │   └── friends.wxss  # 好友页面样式文件
│   ├── login/            # 登录页面
│   │   ├── login.js      # 登录页面逻辑文件
│   │   ├── login.json    # 登录页面配置文件
│   │   ├── login.wxml    # 登录页面结构文件
│   │   └── login.wxss    # 登录页面样式文件
│   ├── myprojectDetail/         # 我的项目详情页面
│   │   ├── myprojectDetail.js   # 我的项目详情页面逻辑文件
│   │   ├── myprojectDetail.json # 我的项目详情页面配置文件
│   │   ├── myprojectDetail.wxml # 我的项目详情页面结构文件
│   │   └── myprojectDetail.wxss # 我的项目详情页面样式文件
│   ├── project/          # 项目广场页面
│   │   ├── project.js    # 项目广场页面逻辑文件
│   │   ├── project.json  # 项目广场页面配置文件
│   │   ├── project.wxml  # 项目广场页面结构文件
│   │   └── project.wxss  # 项目广场页面样式文件
│   ├── projectDetail/         # 项目详情页面
│   │   ├── projectDetail.js   # 项目详情页面逻辑文件
│   │   ├── projectDetail.json # 项目详情页面配置文件
│   │   ├── projectDetail.wxml # 项目详情页面结构文件
│   │   └── projectDetail.wxss # 项目详情页面样式文件
│   ├── receiveapply/         # 接收申请页面
│   │   ├── receiveapply.js   # 接收申请页面逻辑文件
│   │   ├── receiveapply.json # 接收申请页面配置文件
│   │   ├── receiveapply.wxml # 接收申请页面结构文件
│   │   └── receiveapply.wxss # 接收申请页面样式文件
│   ├── register/          # 注册页面
│   │   ├── register.js    # 注册页面逻辑文件
│   │   ├── register.json  # 注册页面配置文件
│   │   ├── register.wxml  # 注册页面结构文件
│   │   └── register.wxss  # 注册页面样式文件
│   ├── user/              # 个人中心页面
│   │   ├── user.js        # 个人中心页面逻辑文件
│   │   ├── user.json      # 个人中心页面配置文件
│   │   ├── user.wxml      # 个人中心页面结构文件
│   │   └── user.wxss      # 个人中心页面样式文件
├── components/            # 自定义组件目录
│   ├── navigation-bar/         # 自定义顶部导航栏组件
│   │   ├── navigation-bar.ts   # 自定义顶部导航栏组件逻辑文件
│   │   ├── navigation-bar.json # 自定义顶部导航栏组件配置文件
│   │   ├── navigation-bar.wxml # 自定义顶部导航栏组件结构文件
│   │   └── navigation-bar.wxss # 自定义顶部导航栏组件样式文件
├── utils/                 # 工具库文件夹,包含公用的工具函数
│   ├── util.js            # 常用工具函数
│   └── request.js         # 网络请求封装
└── images/                # 图片资源文件夹
    ├── friends.png        # 通讯录图片
    ├── index.png          # 项目广场图片
    ├── message.png        # 创建项目图片
    ├── unknown.png        # 搜索图片
    ├── user.png           # 个人中心图片
    ├── 1.png              # 申请页面图片
    ├── 2.png              # 创建项目背景图片
    ├── 3.png              # 项目广场背景图片
    └── no_message.png     # 消息为空显示图片

使用说明:

这是我们小程序的二维码: a34cee2440e5258e30cad74b851fc129

它是有一定的时效的!所以如果想要预览麻烦您先联系一下102201241小戴或102201542小曾获取一下最新的二维码与添加体验成员,谢谢!!

注册和登录🔭

首先!要进入小程序肯定要先注册与登录啦!我们设计一进入小程序便显示“欢迎来到ProjectPartner”和我们小程序的slogan“在这里找到志同道合的小伙伴吧”,以及一个很好看的图片(来自素材网不侵权!)若用户还未有账号,可以点击注册,首先允许用户微信授权,接着设置账号密码。若用户已有账号,则可直接输入账号、密码进入。为了让测试人员更好地体验我们的小程序,我们已向小程序中添加了部分用户、项目等等。测试人员可以通过以下账号、密码登录进行测试:

账号:123

密码:12345

登录后,我们的小程序设计导航栏有四个界面,分别为“项目广场”、“创建项目”、“通讯录“、”个人中心“。接着我就按照这个顺序分别介绍!

项目广场📫

(1)项目广场中有所有的项目,这些项目均来自于用户创建,按时间顺序呈现,最新的呈现在最上面。在项目广场界面可以浏览到所有的项目,同时可以通过界面上方的搜索框进行搜索,会根据用户的输入与项目的名称、创建者昵称、项目描述相匹配,有匹配的字符串便可直接在下方显示。用户可以通过搜索定位到自己感兴趣的项目或创建者。

(2)点击每一个项目,便可进入项目详情界面。项目详情界面包含项目名称、创建人、点赞数、项目描述、项目成员。如果喜欢这个项目,可以点击”点赞“按钮,点赞数会相应增加,点赞数都是实时更新的。同时如果对这个项目感兴趣,可以点击”申请加入项目“按钮,进入申请界面,填写自己的申请理由和联系方式,提交申请后创建此项目的用户会收到该申请;或点击“进入聊天”按钮,进入通讯录界面,与项目中的成员进行联系。

创建项目🌱

在创建项目界面中可输入创建者昵称、项目标题、项目描述,其中设计字数限制分别为10、15、200。当达到字数限制时,用户则不可以再继续输入,同时出现告知用户的提示。填写完毕后,点击“发布项目”按钮,即可成功发布。同时跳转到项目广场界面,用户可以在项目广场上看到自己刚刚创建的项目。

通讯录👋

(1)通讯录界面显示“新朋友”、“我的好友”、“其他用户”三栏。“新朋友”处会显示收到的好友申请,若暂无好友申请会有相关提示,若有则会显示申请用户的头像、昵称,以及“同意”的按钮。点击同意按钮后,该用户则会出现在“我的好友”处。“其他用户”处显示小程序上的所有用户,用户也可以通过搜索框对感兴趣的用户进行搜索,每个用户右侧都会显示“添加好友”按钮,点击即会发送好友申请。

(2)成为好友后,可以点击用户区域,进入聊天。聊天的记录会被实时记录下来。

个人中心🤔

(1)个人中心会显示用户的头像、昵称、账号,以及该用户创建的项目。同时有修改头像的按钮,用户可以选择拍照或者选择相册的方式修改头像。还有一个“切换用户”按钮,点击进入登录界面。

(2)点击项目后会进入我的项目详情界面。这个界面会显示项目名称、项目描述、点赞数、项目成员信息。同时有一个收到的申请按钮。用户点击此按钮可以进入收到的申请界面,点击各个申请可以进入申请详情界面,可以看到申请人昵称、申请理由以及申请人的联系方式,同时有一个“同意”按钮,点击同意即会将该申请人加入为此项目成员中。

PS:若仍有任何不懂的地方或觉得奇怪的地方欢迎联系102201241小戴、102201542小曾

感谢观看✨

6.单元测试

一.选用工具:

目前有多种多种测试工具和框架来确保代码质量和功能的正确性。而我们微信小程序测试选用的是最普遍也是耐用的Jest工具。
Jest 是一个流行的 JavaScript 测试框架,支持单元测试和集成测试。它具有简单的语法和强大的功能,适用于测试小程序的逻辑层,同时还能验证 API 调用、数据库交互、不同模块的配合等。

二.学习过程:

我们先是浏览博客作业中发的邹欣老师的有关“单元测试和回归测试”的文章内容了解单元测试的基本知识。在选择Jest作为工具以后,我们通过浏览网上一些已经有的Jest进行单元测试的教程进行初步学习,有些基础的启蒙视频对我们的帮助还是非常大的,如B站上的这个视频:
【JS测试:Jest框架入门教程】 https://www.bilibili.com/video/BV1WR4y1C7Hv/?share_source=copy_web&vd_source=8d65f83da6438647c18b1676071fa84d
在实际编程中,可以借助AI生成一个大致的测试模板,然后自己根据需求改写,我们在微信小程序的开发过程中会用到wx的各种API来存储数据或者获取数据到我们的云开发的后端数据库,所以我们的测试文件采用的是在一开始时就直接模拟wx的对象对数据库的调用。

三.简易教程:

(1)我们首先得确保自己的电脑安装了Node.js,然后在Node js命令控制台打开我们的项目文件,初始化一下我们的package.json文件:

(2)使用npm安装Jest,具体指令如下:
npm install --save-dev jest
(3)安装好以后,在项目的根目录下创建jest.config.js文件,文件里的内容可以像我们一样定义:

然后就可以在开始编写我们的测试代码啦,你需要创建一个测试文件,例如 example.test.js。在该文件中,你可以编写自己的测试。
(4)最后,在控制台运行npx jest example.test.js就可以查看测试结果了:
呈现结果大致是这样的:

成功通过,nice!

四.部分单元测试代码展示:

以下是跳转功能单元测试代码,实现的测试是在点击项目后是否会跳转到项目详情界面并显示,界面之间的跳转属于是最基础也是最重要的功能,对其测试十分必要!!
测试用到的大部分是基础的模拟函数。

</details>
// project.test.ts
const myapp = {
    globalData: {}
};

// 模拟 wx 对象
global.wx = {
    navigateTo: jest.fn(), // 只模拟 navigateTo 方法
};

// 模拟 getApp 函数
global.getApp = () => myapp;

// 模拟 Page 函数
function Page(obj) {
    Object.assign(this, obj);
}

// 添加 goToDetail 方法
Page.prototype.goToDetail = function (event) {
    const { title, description, account_id } = event.currentTarget.dataset;
    wx.navigateTo({
        url: `/pages/projectDetail/projectDetail?title=${title}&description=${description}&account_id=${account_id}`
    });
};

// 测试用例
describe('Project Page Functionality', () => {
    let pageInstance;

    beforeEach(() => {
        jest.clearAllMocks(); // 清除之前的模拟
        pageInstance = new Page({}); // 创建 Page 实例
    });

    it('should navigate to project detail page with correct parameters', () => {
        const event = {
            currentTarget: {
                dataset: {
                    title: '项目1',
                    description: '描述1',
                    account_id: '001'
                }
            }
        };

        pageInstance.goToDetail(event); // 调用 goToDetail 方法

        // 断言
        expect(wx.navigateTo).toHaveBeenCalledWith({
            url: '/pages/projectDetail/projectDetail?title=项目1&description=描述1&account_id=001'
        });
    });
});

以下是注册功能单元测试代码:

// register.test.js
const app = {
    globalData: {
        userInfo: null // 初始化 userInfo
    }
};

// 模拟 wx 对象
global.wx = {
    cloud: {
        database: jest.fn(() => ({
            collection: jest.fn(() => ({
                where: jest.fn(() => ({
                    get: jest.fn((callback) => {
                        // 默认模拟返回值为空
                        callback.success({ data: [] }); // 初始为空,模拟无重复账户
                    }),
                })),
                add: jest.fn((data) => ({
                    success: jest.fn(() => {
                        // 模拟添加成功
                        return { _id: 'user123' };
                    }),
                })),
            })),
        })),
        switchTab: jest.fn(),
        showToast: jest.fn(),
        getUserProfile: jest.fn((options) => {
            // 模拟用户授权
            options.success({ userInfo: { avatarUrl: 'test_url', nickName: 'test_user' } });
        }),
    },
};

// 模拟 getApp 函数
global.getApp = () => app;

// 模拟 Page 函数
function Page(obj) {
    // 将 obj 绑定到 this
    Object.assign(this, obj);
    this.data = { account_id: '', ps1: '', ps2: '' }; // 初始化 data
}

// 在构造函数中绑定原型方法
Page.prototype.getUserProfile = function () {
    var that = this;
    wx.getUserProfile({
        desc: '展示信息',
        success: (res) => {
            console.log(res);
            that.setData({
                userInfo: res.userInfo
            });
            wx.showToast({
                title: '已授权',
                duration: 500
            });
            // 加入全局变量
            app.globalData.userInfo = res.userInfo;
            console.log(app.globalData.userInfo);
        }
    });
};

Page.prototype.setData = function (data) {
    Object.assign(this.data, data);
};

Page.prototype.registerCheck = function () {
    if (this.data.ps1 !== this.data.ps2) {
        wx.showToast({
            icon: 'error',
            title: '密码不相同',
        });
        return false;
    } else if (this.data.ps1.length > 10) {
        wx.showToast({
            icon: 'error',
            title: '密码过长',
        });
        return false;
    } else if (this.data.account_id.length > 10) {
        wx.showToast({
            icon: 'error',
            title: '昵称过长',
        });
        return false;
    }
    return true;
};

Page.prototype.register = function () {
    var that = this;
    if (!this.registerCheck()) return;

    wx.cloud.database().collection('chat_user').where({
        account_id: that.data.account_id
    }).get({
        success(res) {
            console.log(res);
            // 去除重复用户名
            if (res.data.length > 0) {
                wx.showToast({
                    icon: 'error',
                    title: '昵称重复',
                });
                return;
            } else {
                wx.cloud.database().collection('chat_user').add({
                    data: {
                        avatarUrl: that.data.userInfo.avatarUrl,
                        nickName: that.data.userInfo.nickName,
                        account_id: that.data.account_id,
                        password: that.data.ps2,
                        friends: [],
                        new_friends: []
                    },
                    success(res) {
                        console.log(res);
                        // 将用户名和密码保存到全局变量 app.globalData中
                        app.globalData.userInfo.account_id = that.data.account_id;
                        app.globalData.userInfo.password = that.data.ps2; // 修改为 ps2
                        wx.switchTab({
                            url: '/pages/message/message',
                        });
                    }
                });
            }
        }
    });
};

// 测试用例
describe('Register Functionality', () => {
    beforeEach(() => {
        jest.clearAllMocks(); // 清除之前的模拟
    });

    it('should authorize user profile and set userInfo', () => {
        // 创建 Page 实例
        const pageInstance = new Page({});
        pageInstance.getUserProfile();

        // 断言
        expect(pageInstance.data.userInfo).toEqual({ avatarUrl: 'test_url', nickName: 'test_user' });
        expect(app.globalData.userInfo).toEqual({ avatarUrl: 'test_url', nickName: 'test_user' });
        expect(wx.showToast).toHaveBeenCalledWith({ title: '已授权', duration: 500 });
    });

    it('should register successfully with valid input', () => {
        // 创建 Page 实例并设置用户信息
        const pageInstance = new Page({});
        pageInstance.setData({
            account_id: 'test_user',
            ps1: '123456',
            ps2: '123456',
            userInfo: { avatarUrl: 'test_url', nickName: 'test_user' }
        });

        // 调用注册函数
        pageInstance.register();

        // 断言
        expect(wx.showToast).not.toHaveBeenCalledWith({ icon: 'error', title: '昵称重复' });
        expect(wx.switchTab).toHaveBeenCalledWith({ url: '/pages/message/message' });
        expect(app.globalData.userInfo).toEqual({
            avatarUrl: 'test_url',
            nickName: 'test_user',
            account_id: 'test_user',
            password: '123456'
        });
    });

  

    it('should show error toast for password mismatch', () => {
        // 创建 Page 实例并设置用户信息
        const pageInstance = new Page({});
        pageInstance.setData({
            account_id: 'test_user',
            ps1: '123456',
            ps2: '654321', // 密码不匹配
        });

        // 调用注册函数
        pageInstance.register();

        // 断言
        expect(wx.showToast).toHaveBeenCalledWith({ icon: 'error', title: '密码不相同' });
    });

    it('should show error toast for long password', () => {
        // 创建 Page 实例并设置用户信息
        const pageInstance = new Page({});
        pageInstance.setData({
            account_id: 'test_user',
            ps1: '12345678901', // 密码过长
            ps2: '12345678901',
        });

        // 调用注册函数
        pageInstance.register();

        // 断言
        expect(wx.showToast).toHaveBeenCalledWith({ icon: 'error', title: '密码过长' });
    });

    it('should show error toast for long account_id', () => {
        // 创建 Page 实例并设置用户信息
        const pageInstance = new Page({});
        pageInstance.setData({
            account_id: 'test_user_test', // 昵称过长
            ps1: '123456',
            ps2: '123456',
        });

        // 调用注册函数
        pageInstance.register();

        // 断言
        expect(wx.showToast).toHaveBeenCalledWith({ icon: 'error', title: '昵称过长' });
    });
});

在这里面我们用的了很多测试功能,如:
(1)测试在调用 getUserProfile 方法后,用户信息(如头像和昵称)被正确设置到页面实例和全局数据中。
(2)测试用户在输入有效且唯一的账号信息时,能够成功注册。
(3)确保系统在注册时检查到重复的账号 ID,并给出相应的错误提示。
该单元测试使用的函数大部分为模拟函数,以及清除状态并重置模拟函数beforeEach()。

五.构造数据主要思路:

我们的测试数据,主要是围绕一些违规情况进行构建的,比如说构建一些超过字数限制的字符,重复的id,还有空字符。当然老师和同学们应该会用各种数据为难我们,但我们小组也是测试了很多种情况来应对老师和同学们的测试,主打一个道高一尺,魔高一丈。

7.签入记录:


8.遇到困难以及如何解决:

在整个过程中,代码方面还是遇到很多地方不懂,比如实现小程序API调用,传参数等,虽然都很基础,但是连在一块就很复杂,没办法ddl催着我们不断前进,我们凭借着前人小程序开发的经验也是顺利解决,收获也是颇丰,大大提高了我们的技能。

9.评价:

我的队友小戴同学是非常非常厉害的开发选手,能力十分过硬,基本上很多看起来特别难搞的问题在她手上也是迎刃而解。感觉自己很大程度拖了后腿捏。我的话自己节奏比较缓慢,但有的时候也可以帮助队友稳定情绪,但是我的硬实力还是有些欠缺的,我会加油的

posted @ 2024-10-10 23:42  哎哎呦呦喂喂0211  阅读(12)  评论(0编辑  收藏  举报