软件工程实践2020_作业2
软件工程2020寒假作业2
这个作业属于哪里 | 2020春丨W班 (福州大学) |
---|---|
这个作业的要求在哪里 | 作业要求 |
这个作业的目标 | 创建熟悉使用Github,完成提交疫情统计程序 |
作业正文 | ... |
其他参考文献 | https://www.cnblogs.com/hengyumo/p/12276133.html |
Github仓库地址 | https://github.com/XTG-L/InfectStatistic-main |
Github仓库地址
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
Estimate | 估计这个任务需要多少时间 | 10 | 5 |
Development | 开发 | 8*60 | 10*60 |
Analysis | 需求分析(包括学习新技术) | 30 | 20 |
Design Spec | 生成设计文档 | 30 | 30 |
Design Review | 设计复审 | 30 | 10 |
Design Standard | 代码规范(为目前开发指定合适的规范) | 10 | 5 |
Design | 具体设计 | 20 | 30 |
Coding | 具体编码 | 8*60 | 9*60 |
Code Review | 代码复查 | 2*60 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 2*60 | 2*60 |
Reporting | 报告 | 2*60 | 3*60 |
Test Report | 测试报告 | 60 | 60 |
Size Measurement | 计算工作量 | 500行 | 600行 |
Postmortem & Process Improvement Plan | 60 | 60 | |
合计 | 1630 | 1660 |
解题思路
需求分析
- 读取指定路径下所有格式为YYYY-MM-dd.log.txt的日志文件,统计日志文件的信息并输出到指定的文件
- 支持处理命令行参数
设计思路
-
实现CmdArgs类,用于处理命令行输入的命令(包括分析命令,获取参数及其值,判断命令是否符合规范等)
-
实现CmdList类,用于处理list命令(包括实现具体命令需要的变量,函数等)
-
实现Log类,用于实现对日志文件的判断和处理(包括选择需要读取的日志文件,判断是否为注释行等)
-
实现Region类,用于将日志文件内容转换并保存为Region类并做接下来的处理(包括对地区的排序,人数统计等)
命令从命令行被读取后先由CmdArgs类进行命令的判断,然后进入具体的命令类执行命令 CmdList类中,会调用Log类及其内部Region类进行日志文件的读取和转换 经过Log类和Region类的处理后,Cmdlist会将处理后的数据输出到指定的文件中覆写
实现过程
InfectStatistic类中的main()函数用于接受并传递参数给CmdArgs类
CmdArgs类中的action()函数用于开始执行具体命令
isAssign()函数用于判断一个地区是否为指定地区
isLegal()函数用于判断读入的命令是否符合规范
readLog()函数用于从指定路径下的文件中读取日志文件
regionToLine()函数用于将一个Region类转换为一行要输出的结果
outLog()用于向指定文件覆写结果
Log类中的logToRegion()函数用于将Log类的数据转换为Region类
isIgnore()用于判断日志文件中的一行是否为注释行
rmAfter()用于移除读取队列中指定日期之后的日志文件
sumAll()用于统计全国地区的数据
Region类中的equals()用于判断两个地区对象是否相等
indexOfRegion()用于获取指定地区在动态数组中的下表
RegionToInt()用于统计地区类中存储的动态数组中的数据
sort()用于对地区类进行排序
代码说明
关键函数
- 执行命令
void action() {
try {
readLog(this.logPath, this.files, this.logs);
Log.logToRegion(this.logs, this.regions);
outLog(this.outPath);
} catch (IOException e) {
e.printStackTrace();
}
}
- 读取日志文件并储存在logs里,然后调用logToRegion将日志文件转换并保存
- @param logPath
- @throws IOException
static void readLog(String logPath, String[] files, ArrayList<String> logs) throws IOException {
BufferedReader br = null;
String line = null;
for (String name : files) {
if (name.equals("")) continue;
FileInputStream fis = new FileInputStream(logPath + name);
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
br = new BufferedReader(isr);
while((line = br.readLine()) != null)
if(!Log.isIgnore(line))
logs.add(line);
br.close();
}
}
- 将日志文件转换为地区类并储存
- @param logs
static void logToRegion(ArrayList<String> logs, ArrayList<Log.Region> regions) {
for (String log : logs) {
String[] items = log.split("[\\s]+");
int index = Log.Region.indexOfRegion(regions, items[0]);
int num = 0;
for (String item : items)
if (item.endsWith("人"))
num = Integer.valueOf(item.replace("人", ""));
Log.Region region = regions.get(index);
switch (items[1]) {
case "新增": {
if (items[2].equals("感染患者"))
region.ip.add(num);
else if (items[2].equals("疑似患者"))
region.sp.add(num);
break;
}
case "感染患者": {
if (items[2].equals("流入")) {
region.ip.add(0 - num);
Log.Region another = regions.get(Log.Region.indexOfRegion(regions, items[3]));
another.ip.add(num);
}
break;
}
case "疑似患者": {
if (items[2].equals("确诊感染")) {
region.ip.add(num);
region.sp.add(0 - num);
} else if (items[2].equals("流入")) {
region.sp.add(0 - num);
Log.Region another = regions.get(Log.Region.indexOfRegion(regions, items[3]));
another.sp.add(num);
}
break;
}
case "治愈": {
region.cure.add(num);
region.ip.add(0 - num);
break;
}
case "死亡": {
region.dead.add(num);
region.ip.add(0 - num);
break;
}
case "排除": {
region.sp.add(0 - num);
break;
}
default: {
break;
}
}
}
}
- 向指定路径输出结果
- @param outPath
- @throws IOException
void outLog(String outPath) throws IOException {
Log.Region.sort(regions);
FileOutputStream fos = new FileOutputStream(outPath);
OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
Log.Region all = Log.sumAll(regions);
osw.write(regionToLine(all) + "\n");
osw.flush();
for (Log.Region region : regions)
if(isAssign(this.province, region)) {
osw.write(regionToLine(region) + "\n");
osw.flush();
}
osw.close();
}
单元测试及代码覆盖率截图
单元测试
class InfectStatisticTest {
@Test
void testList() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt"};
InfectStatistic.main(str);
}
@Test
void testLog() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt"};
InfectStatistic.main(str);
}
@Test
void testDate() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt",
"-date", "2020-01-25"};
InfectStatistic.main(str);
}
@Test
void testType() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt",
"-type", "ip", "sp"};
InfectStatistic.main(str);
}
@Test
void testProvince() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt",
"-province", "北京", "福建"};
InfectStatistic.main(str);
}
@Test
void testErrorList() {
String[] str = {"errorlist",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt"};
InfectStatistic.main(str);
}
@Test
void testErrorType() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt",
"-type", "errorType"};
InfectStatistic.main(str);
}
@Test
void testTypeProvince() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt",
"-type", "ip", "sp",
"-province", "北京", "福建"};
InfectStatistic.main(str);
}
@Test
void testDateProvince() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt",
"-date", "2020-01-25",
"-province", "北京", "福建"};
InfectStatistic.main(str);
}
@Test
void testDateType() {
String[] str = {"list",
"-log", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\log\\",
"-out", "C:\\Users\\97680\\Documents\\GitHub\\InfectStatistic\\221701127\\result\\ListOut.txt",
"-type", "ip", "sp",
"-date", "2020-01-25"};
InfectStatistic.main(str);
}
}
代码覆盖率及优化思路
1. 尽量使用正则表达式,避免直接使用固定的字符串
2. 尽量细化函数功能,降低程序粒度,提高代码覆盖率
代码规范
心路历程
- 在进行代码编写之前,先根据需求,确定工作流程,确定整体的框架,之后再编写代码,这样能过减少修改代码结构的次数和时间,减少不必要的工作。
- 在进行测试前,可以编写用于进行测试的函数,方便日后或者是他人的测试
- 代码完成后,还要进行代码优化和覆盖率测试,减少不必要的运行开销