這個作業屬於哪個課程 | https://edu.cnblogs.com/campus/fzu/SE2020 |
---|---|
這個作業要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277 |
這個作業的目標 | 結對編程,學習前端,單元測試,github |
學號 | 031802513-031802516 |
團隊成員
學號 | 姓名 |
---|---|
031802513 | 黃展 |
031802516 | 蘭傑 |
1、開頭:
標題 | 鏈接 |
---|---|
結對同學博客鏈接 | https://www.cnblogs.com/jieblue/ |
本作業博客的連接 | https://www.cnblogs.com/qewpqewp |
倉庫地址 | https://github.com/jieblue/031802513-031802516 |
2、具體分工:
031802513完成js部分和vue的框架構建,單元測試框架
031802516完成html部分,完善單元測試用例,美化頁面
3、PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
---|---|---|---|
Planning | 計划 | 60 | 70 |
Estimate | 估計這個任務需要多少時間 | 5 | 5 |
Development | 開發 | 300 | 350 |
Analysis | 需求分析 (包括學習新技術) | 50 | 100 |
Design Spec | 生成設計文檔 | 25 | 30 |
Design Review | 設計復審 | 15 | 30 |
Coding Standard | 代碼規范 (為目前的開發制定合適的規范) | 10 | 20 |
Design | 具體設計 | 50 | 80 |
Coding | 具體編碼 | 25 | 70 |
Code Review | 代碼復審 | 50 | 60 |
Test | 測試(自我測試,修改代碼,提交修改) | 30 | 350 |
Reporting | 報告 | 25 | 50 |
Test Report | 測試報告 | 10 | 20 |
Size Measurement | 計算工作量 | 5 | 20 |
Postmortem & Process Improvement Plan | 事后總結, 並提出過程改進計划 | 5 | 100 |
合計 | 665 | 1355 |
4、解題思路描述與設計實現說明
-
實現思路
0、此項目用Vue+element-ui實現,測試模塊為jest+vue/test-utils
1、將文本處理,生成樹結構
2、樹結構:{name:"張三",children:[{name:"2018級研究生",children:[{name:"李四",detail:"java"},{name:"王五",}]},{name:"2019級研究生",children:[{name:"趙六"},{name:"陳7"}]}]}
(每個節點有name、detail、children字段)
3、樹合並算法,遍歷每個樹的葉節點,判斷是否有某根節點的name=葉節點的name,如果有,就將此根節點替換成此葉節點
4、將此樹結構傳入Tree組件,Tree組件遞歸形成圖形樹 -
數據流圖
-
代碼片段
樹結構生成算法:將輸入的文本逐行讀取,每行出現“導師:”時,儲存此導師名字,此時進入學員錄入模式,之后的每一行都是該導師學員的信息。當讀取到空行時,結束此導師的錄入模式,重復此過程直到讀取到某非空行且不處於學員錄入模式時,則開始錄入每個學員的具體信息。
initData() {
var nowTeacher = "";//當前教師
this.lines = this.text.split("\n");//以行分割
this.lines.forEach((item) => {//遍歷每一行
if (item.includes("導師:")) {//判斷是導師
var temp = item.split(":");
nowTeacher = temp[1];//開始錄入此導師的子節點的標志
this.teacher.push({ name: temp[1], children: [], extend: false ,image_url : require("../assets/head.jpg")});
} else if (item === "") {//導師后出現空行
nowTeacher = "";//停止導師錄入子節點
} else if (nowTeacher !== "") {//導師的子節點
var temp1 = item.split(":");
var students = temp1[1].split("、");
this.teacher.filter((item) => {
if (item.name === nowTeacher) {
var children = [];
students.forEach((s) => {
children.push({ name: s , image_url : require("../assets/head.jpg")});
});
item.children.push({
name: temp1[0],
children: children,
extend: false,
});
}
});
} else {//判斷是學生的具體信息
var temp2 = item.split(":");//temp2[0]學生姓名,temp2[1]學生詳情
this.teacher.forEach((teacher) => {
if (teacher.name === temp2[0]) {
teacher.detail = temp2[1];
}
teacher.children.forEach((grade) => {
grade.children.forEach((item) => {
if (item.name === temp2[0]) {
item.detail = temp2[1];
return;
}
});
});
});
}
});
},
},
五、附加特點設計與展示
設計的創意獨到之處,這個設計的意義:
- 拖拽功能、結點收縮展開、文件上傳
- 意義:當成員信息較多時,拖拽和結點收縮展開可以使得信息查看更便利,不會占據太多空間,文件上傳可能沒啥意義,后期可改成數據庫讀取
實現思路:
- 1、拖拽:當模塊觸發鼠標左鍵按下事件后,監聽鼠標移動事件,將模塊的位置加上鼠標偏移量,當鼠標左鍵抬起后停止監聽。
- 2、結點收縮展開,由於樹結點是遞歸形成,每個結點的樹結構含有一個extend字段,當此字段為true時,此結點顯示,反之隱藏
- 3、文件上傳(略)
代碼(拖拽功能):
directives: {
//拖拽功能
drag: {
// 指令的定義
bind: function (el) {
let oDiv = el; // 獲取當前元素
oDiv.onmousedown = (e) => {
// 算出鼠標相對元素的位置
let disX = e.clientX - oDiv.offsetLeft;
let disY = e.clientY - oDiv.offsetTop;
document.onmousemove = (e) => {
// 用鼠標的位置減去鼠標相對元素的位置,得到元素的位置
let left = e.clientX - disX;
let top = e.clientY - disY;
oDiv.style.left = left + "px";
oDiv.style.top = top + "px";
};
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
};
};
},
},
},
使用方法:在標簽里面加個 -drag <div v-drag>
成果展示
六、在博客中給出目錄說明和使用說明
目錄組織:
```
├── public index.html默認位置
├── src
│ ├── assets 資源文件夾
│ ├── components 組件
│ ├── router 路由配置
│ └── views 主頁面
└── test
└── unit 單元測試文件
```
運行方式:
- 1 安裝node.js https://nodejs.org/zh-cn/ (12.9.0)
- 2 下載完可檢查在windows任務命令行里輸入node -v
- 3 使用淘寶NPM鏡像源下載比較快 命令:npm install -g cnpm --registry=https://registry.npm.taobao.org
- 4 clone倉庫
- 5 cd 031802513-031802516
- 6 npm install 安裝框架
- 7 npm run serve 運行
- 8 訪問 http://localhost:8080/
七、單元測試
-
測試工具:jest+vue/test-utils
-
安裝方式:在構建vue項目的時候引入jest,之后在項目中npm install @vue/test-utils 安裝vue/test-utils模塊
-
在tests/unit文件夾內創建 xx.spec.js文件,用來寫測試用例
簡易教程(測試用例文件寫法): 1、import { shallowMount } from '@vue/test-utils' //引入 vue/test-utils的 shallowMount函數來掛載需要測試的組件 2、例子
import Vue from 'vue'
import index from '@/components/index'
import { shallowMount } from '@vue/test-utils'
describe('index頁面測試', () => {
//shallowMount掛載測試組件(此函數不生成子組件,mount生成子組件)
const wrapper = shallowMount(index)
//斷言格式
it('驗證是否渲染了頁面按鈕', () => {
expect(button.text()).toEqual('生成')
})
3、 同等性斷言 Equality Asserts
expect(sth).toEqual(value)
expect(sth).not.toEqual(value)
比較性斷言 Comparison Asserts
expect(sth).toBeGreaterThan(number)
expect(sth).toBeLessThanOrEqual(number)
類型性斷言 Type Asserts
expect(sth).toBeInstanceOf(Class)
條件性測試 Condition Test
expect(sth).toBeTruthy()
expect(sth).toBeFalsy()
expect(sth).toBeDefined()
4、運行npm run test:unit
- 單元測試代碼
index.vue 測試
const button = wrapper.findAllComponents({ name: 'el-button' }).at(1)
it('驗證是否渲染了頁面按鈕', () => {
expect(button.text()).toEqual('生成')
})
wrapper.vm.text = "導師:張三"
button.trigger('click');
it('測試按鈕是否能點擊', () => {
expect(wrapper.vm.teacher[0].name).toEqual("張三")
})
it('測試樹生成算法', () => {
wrapper.vm.text = `
導師:張三
2016級博士生:天一、王二、吳五
2015級碩士生:李四、王五、許六
2016級碩士生:劉一、李二、李三
2017級本科生:劉六、琪七、司四
劉六:JAVA、數學建模
李二:字節跳動、京東雲
`
button.trigger('click');
var teacher = wrapper.vm.teacher[0]
expect(teacher.children[0].name).toEqual("2016級博士生")
expect(teacher.children[1].children[2].name).toEqual("許六")
expect(teacher.children[3].children[0].detail).toEqual("JAVA、數學建模")
})
it('測試復雜樹生成算法,當一個導師是另一個導師的學員的情況', () => {
wrapper.vm.text = `
導師:張三
2016級博士生:天一、王二、吳五
2015級碩士生:李四、王五、許六
2016級碩士生:劉一、李二、李三
2017級本科生:劉六、琪七、司四
導師:王九
2013級博士生:劉久、張三、周七
2012級碩士生:李一、王八、許四
劉六:JAVA、數學建模
李二:字節跳動、京東雲
`
button.trigger('click');
var teacher = wrapper.vm.teacher[0]
expect(teacher.children[0].name).toEqual("2013級博士生")
expect(teacher.children[0].children[1].name).toEqual("張三")
expect(teacher.children[0].children[1].children[1].children[2].name).toEqual("許六")
})
tree.vue測試
it('驗證樹根組件是否正確渲染', () => {
expect(wrapper.find('.name').text()).toEqual('張三')
})
it('驗證樹結點數量', () => {
expect(wrapper.findAllComponents(tree).length).toBe(7)
})
it('驗證子節點組件是否正確渲染', () => {
expect(wrapper.findAllComponents(tree).at(1).findAllComponents(tree).at(1).find(".name").text()).toEqual('李四')
})
const button=wrapper.findComponent({name:'el-button'})
it('驗證學生查看詳情按鈕', () => {
expect(button.text()).toEqual('查看詳情')
wrapper.vm.showDetail({name:"李四",detail:"haha"})
expect(wrapper.vm.detail).toEqual("haha");
})
- 測試數據思路,先測試單棵樹的情況,就類似給出的測試數據,然后測試當一個導師是另一個導師的學員的情況,最終結果的樹會合並。測試人員可能會輸入一個不符合命名標准的數據,此代碼並沒有判斷錯誤命名的能力。
8、github 簽入記錄
9、遇到的代碼模塊異常或結對困難及解決方法
最大的困難是單元測試模塊的引入。剛開始引入的時候,所有的測試用例所指向的組件都出現js代碼錯誤,最開始的報錯是"forEach"函數不存在。經多次查找資料,發現是因為jest版本過低,js編碼不支持es6版本,而forEach是es6新引入的特性。
於是手動修改package.json升級模塊,但由於涉及到的模塊特別多,每個模塊的版本又都互相限制,因此會產生各種不支持。
后來嘗試了重新構建項目,引入Karma+Mocha模塊單元測試,但與vue/test-utils不太兼容,對於element-ui無法測試。
最終將vue-cli升級到vue-cli 3版本,並重構項目,才得以成功進行單元測試。
期間非常絕望,花了兩天時間來解決這個問題,重構項目好幾次,幾乎快要放棄了,甚至去詢問唯一認識會vue的學姐,結果告訴我她不會寫測試。
收獲:還是趁早放棄為好,下次可沒有那么幸運了。不能丟了西瓜撿芝麻。
10、評價隊友
* 值得學習的地方:期間一直勸我不要放棄,要堅持
* 需要改進的地方:頁面設計得不好看