第4次作业-结对编程之实验室程序实现
一、作业概述
这个作业属于哪个课程 | http://dwz.date/cts4 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11277 |
这个作业的目标 | 熟悉前端的开发流程,熟悉HTML、CSS、JAVASCRIPT语言以及部分框架 |
结对同学 | 031802225_沈润佳 031802233_王振宇 |
结对同学的博客链接 | https://www.cnblogs.com/izyo/p/13801116.html |
GitHub项目地址 | https://github.com/2441461233/031802225_031802233 |
二、具体分工
031802225 沈润佳:前期资料的收集、前期思路的设计、前期代码的编写、美化代码、博客撰写。
031802233 王振宇:主要代码的编写、单元测试。
三、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
Estimate | 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 560 | 600 |
Analysis | 需求分析 (包括学习新技术) | 400 | 480 |
Design Spec | 生成设计文档 | 30 | 60 |
Design Review | 设计复审 | 30 | 40 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
Design | 具体设计 | 120 | 360 |
Coding | 具体编码 | 480 | 480 |
Code Review | 代码复审 | 60 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 240 |
Reporting | 报告 | 120 | 120 |
Test Report | 测试报告 | 30 | 30 |
Size Measurement | 计算工作量 | 20 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 2050 | 2570 |
四、解题思路描述与设计实现说明
分析需求可知,需要对输入内容进行处理,并且生成师门树和技能树,鉴于本组小朋友开发经验都不足,在上网查阅大量资料之后,决定使用jQuery 框架有着详细教程上手较快的 antv G6,即一个图可视化的引擎,先用html编写文本框,对输入内容进行分析生成 json 对象后引入G6,生成师门树和技能树。
整体思路如下:
鱼骨图展示如下:
数据流图如下:
第0层DFD:
第1层DFD:
各模块详解:
1. 解析文本框内容:
针对每行不同输入(导师、学生信息、学生技能)进行不同处理提取相应信息存于数组。并统计相应的数量,以便之后循环程序的编写。
function submittext() { //解析输入 每个人赋予一个IDD和相应信息数组
var Text = document.getElementById("inputtext").value;
var Lines = Text.split("
");
var teacher = new Array(), nameLine = new Array();
var name = new Array();
// teacher标识是否是导师,degree标识学位,year标识年级,
// nameLine存每行完整信息,nameString存:后内容,name存名字
var branch = 0;
for (var i = 0; i < Lines.length; i++) {
if (Lines[i].length == 0) { //跳过空行
continue;
}
teacher[i] = Lines[i].substr(0, 2); //分割前两个字,判断是否是“导师”
if (teacher[i] == "导师") { //导师处理
ID++; //每个人独有ID
degree[ID] = "导师"; //degree导师
NAME[ID] = Lines[i].substring(3);
degreenum[teachernum] = 0;
teachernum++;
}
else if(/^d+$/.test(teacher[i])) { //非导师处理
var temp1 = Lines[i].substring(0, 4); //temp1为年级
var temp2 = Lines[i].substr(5, 2); //temp2为学位等级
var tempNameString = Lines[i].substring(Lines[i].search(":") + 1);
name[i] = tempNameString.split("、");
degreenum[teachernum - 1]++;
for (var j = 0; j < name[i].length; j++) { //每个人分配ID 并且存储相关信息
ID++;
year[ID] = temp1;
degree[ID] = temp2;
NAME[ID] = name[i][j];
// studentnum[branch]++;
}
studentnum[branch] = name[i].length;
branch++;
}
//技能树生成
else {
linestr = Lines[i];
var posi = linestr.search(":");
var stuName = linestr.substring(0, posi);
var tempAttris = linestr.substring(posi+1).split("、");
attris[stuName] = tempAttris;
console.log(attris);
}
}
}
2.将文本框获取内容生成json对象
G6 的数据源要求为json对象。因此需将所获信息转换json对象。我们采用动态创建,根据之后生成的树创建父子节点。下一层为上一层的孩子结点。
var IDD = 0; var kk = 0; var kkk = 0;
for (var k = 0; k < teachernum; k++) {
IDD++;
// console.log("teacher="+teachernum);
var test2 = { id: NAME[IDD], children: [] };
for (var i = 1; i <= degreenum[kk]; i++) {
// console.log(kk+" =="+degreenum[kk]);
var xxx = new Object();
xxx.id = year[IDD + 1] + degree[IDD + 1];
xxx.children = new Array();
for (var j = 1; j <= studentnum[kkk]; j++) {
var yyy = new Object();
IDD++;
yyy.id = NAME[IDD];
yyy.children = new Array();
// 增加个人经历
if(attris.hasOwnProperty(yyy.id)) {
console.log("has");
for(var k = 0; k < attris[yyy.id].length; k++) {
var yyychild = new Object();
yyychild.id = attris[yyy.id][k];
yyychild.children = new Array();
yyy.children.push(yyychild);
}
}
xxx.children.push(yyy);
}
test2.children.push(xxx);
kkk++;
}
kk++;
hell = JSON.stringify(test2);
3.根据json对象,使用G6引擎并生成师门树
function pk(data) {
// function test2(hell){
// console.log("xxxx");
// console.log("typeof data is "+typeof data);
// console.log(data);
// console.log("yyyyy");
// function pick (data=hell) {
var graph = new G6.TreeGraph({
container: 'mountNode',
800,
height: 1200,
pixelRatio: 2,
modes: {
default: [{
type: 'collapse-expand',
onChange: function onChange(item, collapsed) {
var data = item.get('model').data;
// console.log("type of this shit is",typeof data);
// console.log(data);
data.collapsed = collapsed;
return true;
}
}, 'drag-canvas', 'zoom-canvas']
},
}
参考链接:
使用其中的 TreeGraph
参考链接:https://antv-g6.gitee.io/zh/docs/manual/getting-started
使用 JQuery UI 组件库
参考链接:https://www.runoob.com/jqueryui/jqueryui-use.html
注意
-
区分json字符串和json对象!
-
引入 G6 的数据源为 JSON 格式的对象
-
jquery ui 是基于 jquery 的 UI 库,提供的是UI组件库;
而jquery是工具库;
五、附加特点设计与展示
设计意义
- 任意拖动生成树 ,支持结点缩放→ 帮助老师同学快速了解自己的同门学长学姐学弟学妹,以及快速了解自己和同学伙伴们的技能。
- 师门技能树可以变大变小 → 万一有同学近视呢?
- 一键清空按钮 → 便于同学一键删除所有信息,重新输入
- 贴心的输入格式导航→方便同学按照规定格式输入文本内容
实现思路
-
一键清空:引入清空的函数
-
生成树的优化:使用 G6 引擎
代码详解
- 一键清空的函数
function cleartext() {
location.reload();
}
-
使用G6 引擎美化图图
function pk(data) { // function test2(hell){ // console.log("xxxx"); // console.log("typeof data is "+typeof data); // console.log(data); // console.log("yyyyy"); // function pick (data=hell) { var graph = new G6.TreeGraph({ container: 'mountNode', 800, height: 1200, pixelRatio: 2, modes: { default: [{ type: 'collapse-expand', onChange: function onChange(item, collapsed) { var data = item.get('model').data; // console.log("type of this shit is",typeof data); // console.log(data); data.collapsed = collapsed; return true; } }, 'drag-canvas', 'zoom-canvas'] }, /******************美化****************/ defaultNode: { size: 16, anchorPoints: [[0, 0.5], [1, 0.5]], style: { fill: '#CCFF00', stroke: '#d91808' } }, defaultEdge: { shape: 'cubic-horizontal', style: { stroke: '#000000' } }, layout: { type: 'compactBox', direction: 'LR', // nodeSep:30, // rankSep:100, getId: function getId(d) { return d.id; }, getHeight: function getHeight() { return 16; }, getWidth: function getWidth() { return 16; }, getVGap: function getVGap() { return 10; }, getHGap: function getHGap() { return 100; } } }); graph.node(function (node) { return { size: 26, style: { fill: '#CCFF00', //节点颜色 stroke: '#2BD54D' //节点边框 }, label: node.id, labelCfg: { position: node.children && node.children.length > 0 ? 'left' : 'right' } }; });
实现成果展示
六、目录说明和使用说明
目录组织形式
zy2.html 为HTML代码编写
zy2.js 为js代码编写
其余为支撑库
运行网页的方法
下载库中所有文件并保证本地相对路径的一致性,打开zy2.html即可运行。
输入内容请按照文本框内的提示输入。
得到生成树后可任意拖拽,并可用滚轮调整页面。
七、单元测试
测试工具:
Mocha、白盒测试用例
白盒测试用例简单教程
- 了解白盒测试用例:白盒测试就是一种设计用例的方法,用白盒测试产生的测试用例能够保证一个模块中的所有独立路径至少被使用一次。
- 具体步骤:规规矩矩按照文本框提示填写 → 生成期望的师门技能树。
(样例图如上目标成果展示)
基于 Mocha 单元测试简易教程(纯小白摸索历程)
-
了解单元测试:面向最小的功能单元模块的测试,比如,面向函数的测试?
-
安装:请移步一下参考链接
-
配置好单元测试的目录文件。
最简单的配置为.test.js和.js文件,其中.test.js用于测试.js
而本次单元测试我们的目录配置如下
-
测试代码的编写
-
进行单元测试,进入.js所在目录
mocha 测试文件名.test.js
-
单元测试完成√
参考链接:
部分单元测试代码
var submittext = require('../attritest.js');
var expect = require('chai').expect;
describe('技能树测试', function() {
it('刘六:JAVA、数学建模', function() {
expect(submittext("刘六:JAVA、数学建模")['刘六']).to.include('JAVA');
});
it('李二:字节跳动、京东云', function() {
expect(submittext("李二:字节跳动、京东云")['李二']).to.include('京东云');
});
});
解说:对题目所给样例进行分模块拆分测试。
构造测试数据的思路,如何应对测试人员的刁难
首先输入数据必须满足格式要求,在此基础上构建数据
- 名字过长? → 并不影响 √
- 技能过多? →并不影响 √
如果是测试人员的故意刁难?
-
不好好按照规定格式输入数据? → 和测试人员好好沟通!
-
输入无关数据(并非师门关系或者技能)→ 那就微笑这看着测试人员!
八、GitHub代码签入记录截图
九、困难以及克服困难
-
对前端知识不熟悉
- 做出尝试:查阅教程、游览大量博客。
- 目前解决 √
- 收获:学会速读教程,需要什么学什么
-
写出了跑不出来树的代码且不知道自己错哪里了
- 做出尝试:疯狂debug,实在不行抛弃源代码
- 目前解决 √
- 收获:做无用功也不能崩心态
- 有人要看一下我打残的代码吗?有大佬指导我一下吗?(丢人ing:https://github.com/qtzj/031802225_031802233/branches)
-
熬夜饿了
- 做出尝试:吃平和舍友的柚子和新疆舍友的烤馍片
- 目前解决√
- 收获:舍友的东西真好吃。
十、评价队友
评价王振宇同学:是一个很不错的队友呀,代码能力比我好却并没有嫌弃我打的乱糟糟的代码,还帮我找了一些错误。
评价沈润佳同学:做事认真仔细收集、整理资料能力强、文字撰写能力强规划性强,能够及时提醒队友