OO-Unit3-总结
OO-Unit3-总结
1.JML规格设计策略
由于JML的规格描述较复杂,本单元的JML规格设计我往往采用由简入难的迭代开发策略。
即一开始不着急开发出最为复杂,性能最好的代码,先严格按照JML描述写一遍代码,实现基本功能。比如类似public instance model non_null Person[] acquaintance;
这样的规格,第9次作业开始时先直接按照ArrayList
处理,这样各个函数中实际的代码和JML描述近乎一致,方便检查。之后在完成了基本功能后,在已经理解了基本功能描述后,对各个容器和方法算法性能进行优化设计迭代。
同时,一般简单的方法和容器设计虽然性能较差,但正确性一般较好,因此个人认为也可以作为之后的迭代优化版本的正确性测试参考的标程(不过实际开发过程中也不可能先开发一版低性能保证正确性,所以还是直接全盘考虑好再写高效一点)。
对于每个方法而言。先确定normal_behavior
和exceptional_behavior
。确定进入函数后不同参数对应的分支条件。并把条件判断语句写好,搭好基本框架。之后再看assignable
会涉及到的变量。再根据ensures
确定结果返回值和应该如何改动变量。对于异常处理里的分支逻辑也是类似的编写方式。此外,每个方法编写时也可以通过函数名字推敲涵义,从而提高正确性。
同时对于迭代增量开发,每次都要重新阅读之前实现过的方法内的JML规格,因为可能会发生变化,比如第二次到第三次作业中的sendMessage
方法。此外要特别注意JML没写出,但是你需要实现的代码,比如MyGroup内的delPerson方法
,如果输入的person
是个null
需要直接返回;MyPerson
类内需要加一个addAcquaitance
方法以及getAcquaitance
方法等。
2.JML测试方法和策略
本单元的JML规格设计由于JML细节较多,很难保证某一份代码是完全正确的,因此测试上最方便最简单的当然就是多人对拍找少数派(即多人运动)的方式了。这个方法在第一单元中也用到过,总结来说,对于这种输入一样,输出结果就应该一样的代码,这种方式测试效率还是很高的。此外,还有Junit单元测试,以及openJML等其他JML工具。
Junit单元测试
Junit测试简单,可以进行对类内每个方法编写自己的测试逻辑。IDEA里最简单的使用方式就是右键点击代码里的类名-->点击Go to-->点击Test
,选择需要测试的函数和选项,就生成了测试文件。
本单元中主要针对一些比较容易出现错误的方法比如isCircle
和queryBlockSum
进行了测试,以这两个函数为例。
import com.oocourse.spec3.exceptions.PersonIdNotFoundException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class MyNetworkTest {
private final MyPerson pa = new MyPerson(1, "a", 12);
private final MyPerson pb = new MyPerson(2, "b", 13);
private final MyPerson pc = new MyPerson(3, "c", 14);
private final MyPerson pd = new MyPerson(4, "d", 15);
private final MyPerson pe = new MyPerson(5, "e", 16);
private final MyPerson pf = new MyPerson(6, "f", 16);
private MyNetwork net = new MyNetwork();