学号1:211606367 姓名:林恩 学号2:211606445 姓名:肖志豪
一、预估与实际
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 690 | 650 |
• Analysis | • 需求分析 (包括学习新技术) | 70 | 50 |
• Design Spec | • 生成设计文档 | 50 | 70 |
• Design Review | • 设计复审 | 20 | 30 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
• Design | • 具体设计 | 185 | 185 |
• Coding | • 具体编码 | 185 | 185 |
• Code Review | • 代码复审 | 30 | 30 |
• Test | • 测试(自我测试,修改代码,提交修改) | 120 | 120 |
Reporting | 报告 | 60 | 50 |
• Test Repor | • 测试报告 | 30 | 30 |
• Size Measurement | • 计算工作量 | 10 | 10 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 10 | 20 |
合计 | 780 | 730 |
二、需求分析
需要了解Junit如何使用以及相关要求:
测试要求
- 测试方法上必须使用@Test进行修饰
- 测试方法必须使用public void进行修饰,不能带任何参数
- 新建一个源代码目录来存放我们的测试代码
- 测试类的包应该和被测试类保持一致
- 测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖
- 测试类使用Test作为类名的后缀(不是必须的)
- 测试方法使用test作为方法名的前缀(不是必须的)
测试失败的两种情况
- Failure一般由单元测试使用的断言方法判断失败所引起的,这经表示测试点发现了问题,就是说程序输出的结果和我们预期的不一样
- error是由代码异常引起的,他可以产生于测试代码本身的错误,也可以是被测试代码中的一个隐藏的bug
- 测试用例不是用来证明你是对的,而是用来证明你没有错;即测试用例不能证明你逻辑上的错误,只能检测出你代码中的错误
执行顺序
@BeforeClass - @Before - @Test - @After - @AfterClass
@BeforeClass:它会在所有方法运行前被执行,static修饰
@Before:会在每一个测试方法被运行前执行一次
@Test:将一个普通的方法修饰成为一个测试方法
xx.class为捕获异常类
@Test(expected = xx.class)
@Test(timeout = 毫秒)
@Ignore:所修饰的测试方法会被测试运行器忽略
@RunWith:可以更改测试运行器 org.junit.runner.Runner
@After:会在每一个测试方法运行后被执行一次
@AfterClass:它会在所有方法运行结束后被执行,static修饰
- @BeforeClass修饰的方法会在所有方法被调用前被执行
- 而且该方法是静态的,所以当测试类被加载后接着就会运行它
- 而且在内存中它只会存在一份实例,他比较适合加载配置文件
- @AfterClass所修饰的方法通常用来对资源的清理,如关闭数据库的连接
- @Before和@After会在每个测试方法的前后各执行一次
- @Before和@After会在每个测试方法的前后各执行一次
- @Before和@After会在每个测试方法的前后各执行一次
测试套件(批量执行测试用例)
测试套件就是组织测试类一起运行的
写一个作为测试套件的入口类,这个类里不包含其他的方法
更改测试运行suit.class
将要测试的类作为数组传入Suite.SuiteClasses({})
@RunWith(Suite.class)
@Suite.SuiteClasses({TaskTest1.class,TaskTest2.class,TaskTest3.class})
Junit参数化测试
更改默认的测试运行器为RunWith(Parameterized.class)
声明变量来存放预期值和结果值
声明一个返回值为Collection的公共静态方法,并使用@Parameters进行修饰
为测试类声明一个带有参数的公共构造函数,并在其中为之声明变量赋值
三、设计
1. 设计思路
说明你如何设计这个程序
设计单元测试的思路
- assertEquals()和assertRaises(),比对方法返回值和逻辑值的差别,来检验方法的是否执行有效成功
- 若是有的方法没有返回值,则先实例化,然后比对方法中的值和逻辑值的差别也是可以的
- 有些需要赋予某些其它的初始值
单元测试
-
部分单元测试代码
请展示一段程序的关键代码,并解释代码的作用
@Test
public void testMain() {
String[] args = {"-n", "100", "-grade", "3"};
MathExam math = new MathExam();
math.main(args);
assertEquals(true, math.output_boolean);
}
测试方法上有@Test才会进行测试运算。先实例化,然后传参,math.output_boolean初值为false,执行完代码后math.output_boolean会赋值为true,代表执行完成。这时候只需要判断下值是否为true,即可代表main()是否执行成功。
要对各种可能的值进行测试,确保能够实现方法的各种可能
-
单元测试覆盖率截图
结构优化
- UML类图:
- 程序运行流程图
程序做出重构的部分,与重构的原因
- 重构了关于两个数字的计算与判断,在原先代码里关于数字的计算判断大量重复,所以我将它生成为一个方法类与生成式子的类合并
- 将生成式子的类从原先类中提取出,专门生成个类来生成式子以及判断,为了让每个类的模块与功能都更加精准、
重构后每个模块的功能
- MathExam类(主类,自身负责生成和写入文件,以及调用其它方法类来生成式子)
- Two_Numbers类(负责生成一年级和二年级式子以及子式判重,防止生成重复的式子包括子式,在生成三年级式子时调用Calculation类)
- Calculation类(负责三年级式子,转成中缀表达式以及后缀表达式求和)
性能调优
- 贴出优化前效能分析工具的结果截图
-
描述程序的性能瓶颈
- 在代码中存在着大量的重复代码,有些代码冗余无法行之有效实现功能
-
给出优化方案
- 进行了一定量的代码缩减提取,删减某些无用或者重复的代码
-
贴出优化后效能分析工具的结果截图
2. 实现方案 写出具体实现的步骤
分为三个步骤:
单元测试
- 针对程序架构,进行单元测试,确保每个模块能够达到预期的要求
结构优化
- 把具有相似功能的代码封装在一起
- 思考代码应该怎么进行结构优化
- 每当代码的一个模块完成了重构,就需要commit
- 为了保证每次重构后代码的正确性,我们需要先进行回归测试,再commit代码
性能调优
- 测试并改进程序生成四则运算算式的效率
- 帮我们分析找到代码中执行效率最差,也就是所谓 效能瓶颈 的部分。就可以把精力花费在改进瓶颈上,从而高效快速地提升程序性能
四、编码
调试日志
记录编码调试的日志,请记录下开发过程中的 debug 历程
比如:
-
在代码的什么位置,代码出现了什么问题,问题会导致什么结果,怎么解决的
- 在调试代码时,一旦更改代码,也需要在测试代码处进行及时的相对应更改
- 对参数的传递方式,有两种,值传递和引用传递,在方法传递的参数中是值传递,更改子方法中的的值是不会修改到父方法相对应的值
-
请说明你如何按照设计思路进行编码,并记录你在开发中遇到的问题,与解决过程
- 在写测试时,查找到有两种方法assertEquals()和assertRaises()。了解到这两种方法各自作用,通过比较object判断不同来返回测试结果,如果相同,测试通过;反之,不通过。这对方法的模块化程度有着一定的要求。后来我想了些方法,不必通过一定要有方法返回值来判断。因为实现方法后,方法内的某些参数必然改变,这时候只要检验到这个方法的应该实现的内容达到逻辑上的值即可。
- 需要对代码的命名,意义,规范有着很深的认识,毕竟不仅仅是自己一个人在编程,需要让其他人看懂读懂,了解代码。也方便自己后期阅读,修改,重构。
五、总结
- 关于计算机题目重复特点,我总结了几个:
- 题目完全相同
- 题目不同,在顺序上不同,式子不同,但是子式相同,只是改变了形式。其实实质是相同的,结果相同
- 比如a + b和b +a,a x b和b x a,
- 最终决定在生成式子时,加上一个采集子式的集合用来判断子式是否重复