OOpre_HW3 and JUnit
一.关于OO_checkstyle的新发现
- 只能采用驼峰命名法命名变量
- 方法行数不超过60行(后续重构代码将操作与处理输入分离的主要原理,虽然只有两分)
- 每行字数不超过100(方法传参时发现)
- 其余关于空格的问题省略
二.增量开发的思路
- 在此次作业中,新增了“食物”、“背包”等概念。
food作为与equipment和bottle同级物品,背包则负责容纳这些物品。 - 新增操作:
- 尝试携带(放入背包)某物品(保证尝试携带的物品冒险者已经拥有)
- 尝试使用某物品(该物品必须被携带才能够使用)
实现逻辑:我们需要明白“携带”与“使用”的业务逻辑。
- 我的第一版代码实现思路
我第一版代码中,按照题目描述,将food与package作为新建类处理,冒险者与背包之间的关系使用哈希表处理,建立起<advid,package>的映射,在背包中建立三个容器分别存储瓶子,装备和食物。对于加入背包,我的理解是,为冒险者增加物品是将物品放在冒险者对应的类adventure.java中对应的总库三个容器中,加入背包需要将物品从总库移动到与冒险者对应的背包,从物理角度来看是对物品进行了移动。这导致实现起来非常麻烦,例如统计数量等都需要考虑两个部分。这与题意不符,具体体现在中测最后一个数据点不过。
- 第二版代码
经过与助教的沟通,我理解到:
放入背包是一个概念的问题,而不是一个物理上的问题。放入背包并不需要将物品从总库中删除,只需要加入背包。
一开始处理中建立冒险者与背包对应哈希表的想法并不符合面向对象的逻辑,这是面向过程的思路,如果想要具体实现背包应该建立在冒险者类中
既然放入背包是一个概念问题,那么我们完全可以不去实现背包实体,而只需要进行概念上的判断。例如给每个物品增加一个属性
1private boolean becarried ;初始时设置为
false即不在背包中,放入背包即建立方法将属性设置为true.这个思路在实现代码上是十分简便的,具体体验到的优势如下:- 不需要新建数据结构存储放在背包中的物品
- 判断该物品是否在背包中只需要获取属性
becarried - 删除物品只需要在
adventure类中的总库删除,实现简洁 - 获取物品数量是需要获取总库中的数量
三.代码架构与重构
经过checkstyle与JUnit对于代码架构的步步限制,我经历了三次代码重构,第一次是在编写过程中发现方法的行数不能超过60行,第二次是在传参时受到限制,选择将定义的静态方法从operation.java移动到inputhandler.java,第三次是编写JUnit过程中由于不能进行输入输出重定向等测评机认为的违法操作,这样只能将输入集中到一个类中,后续在方法中进行读取已经存储好的输入。
对于输入的类,原码如下
| |
这样所有的操作指令被以分割的字符串的方式存入inputinfo,后续将inputinfo传入inputhandler类进行处理,所有的变量从这个形式上的二维数组中读取。这样可以避免在编写JUnit时无法控制台输入导致无法测试方法导致覆盖率不够,第二部分任务寄掉的问题。
详解输入解析
| |
四.JUnit
- 编写
JUnit时由于导入头文件错误,且测试方法前没有写@Test导致测评机无法识别,此处提供JUnit模板
| |
- 编写时常用到的
JUnit4标准断言
| 方法 | 介绍 |
|---|---|
assertEquals(expected, actual) | 检查两个值是否相等 |
assertTrue(condition) | 检查条件是否为真 |
assertFalse(condition) | 检查条件是否为假 |
assertNotNull(object) | 检查是否不为空 |
assertNull(object) | 检查是否为空 |
assertNotSame(expected, actual) | 检查两个相关对象是否不指向同一个对象 |
assertSame(expected, actual) | 检查两个相关对象是否指向同一个对象 |
assertArrayEquals(expectedArray, resultArray) | 检查两个数组是否相等 |
注:使用assert()断言是测评机不识别的,会导致本地覆盖率与测评结果差距较大
运行测试代码报错空指针
编写
inputhandler.java中的测试方法时,由于有删除,携带等操作,前提是必须有对应的冒险者,对应的物品,所以想要测试这个方法需要连带调用前提方法,如果不建立前提就会出现空指针。这里的测评方法同样是采用建ArrayList<ArrayList<String>>类型并进行赋值。相对来说对inputhandler的测试是最为复杂的。