軟體工程第二次結隊作業

哎哎呦呦喂喂0211發表於2024-10-10
這個作業屬於哪個課程 軟體工程 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 1350

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.評價:

我的隊友小戴同學是非常非常厲害的開發選手,能力十分過硬,基本上很多看起來特別難搞的問題在她手上也是迎刃而解。感覺自己很大程度拖了後腿捏。我的話自己節奏比較緩慢,但有的時候也可以幫助隊友穩定情緒,但是我的硬實力還是有些欠缺的,我會加油的

相關文章