第一次个人编程作业

仓库地址

PSP

PSP2.1 Personal Software
Process Stages
预估耗时(min) 实际耗时(min)
Planning 计划 54 54
Estimate 估计这个任务需要多少时间 54 54
Development 开发 792 880
Analysis 需求分析
(包括学习新技术)
90 90
Design Spec 生成设计文档 54 40
Design Review 设计复审 54 20
Coding Standard 代码规范
(为开发制定合适的规范)
27 10
Design 具体设计 108 100
Coding 具体编码 189 360
Code Review 代码复审 60 60
Test 测试
(自我测试,修改,提交修改)
189 200
Reporting 报告 54 54
Test Report 测试报告 18 18
Size Measurement 计算工作量 9 9
Postmortem & Process
Improvement Plan
事后总结
并提出过程改进计划
27 27
合计 900 988

解题思路

**step 1. **利用正则表达式提取姓名和手机号码, 并将其从原字符串中去除

**step 2. ** (Level 1) 利用中国省市区街道四级联动json数据逐级匹配地址,对于缺字的情况,取前两个字当作关键词匹配。对于缺级的情况,遍历上一级所有子级的子级匹配。虽然总数据量较大,但是实际上每次分级之后可以少检索很多数据。

**step 3. ** (Level 2) 利用正则表达式分割剩余的详细地址

**step 4. ** (Level 3) 调用高德Api

**step 5. ** 使用Moshi库将结果对象转换成Json输出

设计实现过程

数据类

类名 说明 属性
Data 数据 provinces
Result 结果 name, phone, address
Province 省级 name, cities
City 地级 name, areas
Area 县级 name, streets
Street 街道 name

工具类

类名 作用
FileUtil 读取和写入文件
JsonUtil 转换对象和Json字符串
Trimmer 处理输入样例

主要函数

函数名 说明
void Data.build() 用json数据生成所需对象
void trimName() 切去姓名
void trimPhone() 切去手机号
void trimProvince() 切去省级
void trimCity(List<City>) 切去地级
void trimArea(List<Area>) 切去县级
void trimStreet(List<Street>) 切去街道
void trimDetail() 切分详细地址

单元测试 (with JUnit 5)

设计

这个题输入比较稳定,只是有可能缺失某几级地址,可以考虑为每个缺失设计一个caseN()测试函数,手动输入样例和答案,例如:

@Test
public void case15() {
    String testCase = "2!甘鞋,甘肃兰州西固区西柳沟街道18629411660什么花园.";
       String name = "甘鞋";
          String phone = "18629411660";
          String[] address = new String[]{
                  "甘肃省",
                  "兰州市",
                  "西固区",
                  "西柳沟街道",
                  "",
                  "",
                  "什么花园"
          };
          resultTest(testCase, name, phone, address);
      }

用resultTest函数验证正确性:

private void resultTest(String testCase, String expectedName, String expectedPhone, String[] expectedAddress) {
    Result result = new Trimmer(testCase).trim().toResult();
    String message = testCase + System.lineSeparator() + result.toString();
    Assert.assertEquals(message, expectedName, result.getName());
    Assert.assertEquals(message, expectedPhone, result.getPhone());
    Assert.assertArrayEquals(message, expectedAddress, result.getAddress().toArray());
}

如果结果与预期有误,则调用assertEquals输出错误信息,方便调试:

测试结果

一共设计了15个不同情况的case,经过疯狂调试,终于全部通过。

完整单元测试代码

测试覆盖率

分割地址用的主要是Trimmer类,除了getter和setter都覆盖到了。其余没覆盖到的也主要是getter和setter。

异常处理

异常主要发生在Trimmer类的方法里,主要是由于输入错误导致的,这样的异常不好正确处理,这里简单地将trim方法包裹在try代码块里,执行时判断输入是否符合要求,如果不符合,中断执行,并直接返回一个空的结果,避免了程序直接退出。

 @Test
    public void exceptionCase1() {
        String testCase = "甘鞋,甘肃兰州西固区西柳沟街道18629411660什么花园.";
        resultTest(testCase,"","",new String[]{});
    }

代码分析 (with Codacy)

根据提示消除了了所有Issue.

性能测试 (with JProfiler)

程序中最占内存的是解析json数据构造出来的String对象,最耗时的操作是解析Json数据。为了提高效率,可以考虑把Json解析器换成FastJson。

收获

这一次还是收获满满的,学会了很多东西:

  • 用JUnit做单元测试;
  • 用JProfiler做性能分析;
  • 用Codacy做代码分析;
  • 用Gradle构建项目,并把所需依赖打包到Jar文件里;

其中最有用的要数单元测试了,可以很方便的测试出Bug来,并修改完代码之后可以反复运行,效率很高,相比以前手动测试,节省了不少时间。代码分析工具可以检测出代码中不合理的地方,并给出修改提示,按照提示修改代码,可以提高代码的可读性和健壮性。

posted @ 2019-09-13 19:06  zaqny  阅读(563)  评论(11编辑  收藏  举报