相信很多同学都发现,每次的软件构造实验都要求我们进行测试代码的编写,而且课程中也很重视测试对于编程的作用,那么测试为什么这么重要呢,我们又该根据什么原则编写测试代码呢,本文就此问题给出笔者的一些看法。
测试为什么那么重要
在软件开发的过程中,我们提倡测试驱动开发(TDD)的方法,原因正是基于测试的重要性:
1.测试是提高软件质量的重要手段
2.测试可以确认开发的程序是否达到用户需求
3.测试可以具体关注系统的某一特定方面的质量特性
4.先进行测试可以节省大量的调试时间
注:测试并不能保证程序100%没有错误!
我们该如何进行测试
按照老师PPT上的介绍,良好的测试应该有如下特点:
1.能发现错误
2.不冗余
3.体现最佳特性
4.别太复杂也别太简单
而测试也是分层级的,从低到高依次为:
单元测试: 是指对软件中的最小可测试单元进行检查和验证,Java里单元指一个类或一个方法
集成测试:也叫组装测试或联合测试。在单元测试的基础上,将所有模块按照设计要求组装成为子系统或系统,进行测试
系统测试:是对整个系统的测试,将硬件、软件、操作人员看作一个整体,检验它是否有不符合系统说明书的地方
验收测试:是部署软件之前的最后一个测试操作。在软件产品完成了单元测试、集成测试和系统测试之后,产品发布之前所进行的软件测试活动。
此外还有回归测试,它指的是修改了旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。
测试方法有白盒测试和黑盒测试:
白盒测试:对程序内部代码结构的测试 ,要考虑内部实现细节
黑盒测试:对程序外部表现出来的行为的测试,黑盒测试完 全从函数spec导出测试用例,不考虑函数内部实现
而我们实验中主要采用的方法是根据等价类的划分来编写测试样例:
基于等价类划分的测试:将被测函数的输入域划分为等价类,从等价类中导出测试用例
针对每个输 入数据需要满足的约束条件划分等价类
每个等价类代表着对输入约束加以满足/违反的有效 /无效数据的集合 。
而相似的输入,将会展示相似的行为。
故可从每个等价类中选一个代表作为测试用例即可
可以按照下面的准则划分:
输入数据限定了数值范围
输入数据指明了特定的值
输入数据确定了一组数
输入数据是Y/N
笛卡尔积做到全覆盖和对于每个维度的取值则至少覆盖一次即可,测试完备,但用例数量多,前者测试代价高 但是并非所有组合情况都可能,后者测试用例少,代价低,但测试覆盖度未必高,通常情况下在这两个方案之间选取一个折衷的方案。
以Lab2中ConcreteVerticesGraph的部分测试代码为例,读者自行体会这种以等价类划分为基础的测试样例编写:
// Testing strategy
// 按照加入的点划分:点已经存在,点不存在
// 按照加入的权值划分:权值为0,权值大于0,权值小于0
@Test
public void testAddsource() {
Vertex<String> vertex = new Vertex<String>("a");
assertEquals(0, vertex.addSource("b", 5));
assertEquals(0, vertex.addSource("c", 3));
assertEquals(5, vertex.addSource("b", 4));
assertEquals(4, vertex.addSource("b", 0));
assertEquals(-1, vertex.addSource("b", -1));
}
// Testing strategy
// 按照加入的点划分:点已经存在,点不存在
// 按照加入的权值划分:权值为0,权值大于0,权值小于0
@Test
public void testAddtarget() {
Vertex<String> vertex = new Vertex<String>("a");
assertEquals(0, vertex.addTarget("b", 5));
assertEquals(0, vertex.addTarget("c", 3));
assertEquals(5, vertex.addTarget("b", 4));
assertEquals(4, vertex.addTarget("b", 0));
assertEquals(-1, vertex.addTarget("b", -1));
}
// Testing strategy
// 按照移除的点划分:点已经存在,点不存在
@Test
public void testRemovesource() {
Vertex<String> vertex = new Vertex<String>("a");
vertex.addSource("b", 5);
vertex.addSource("c", 3);
assertEquals(0, vertex.removeSource("d"));
assertEquals(5, vertex.removeSource("b"));
}
// Testing strategy
// 按照移除的点划分:点已经存在,点不存在
@Test
public void testRemovetarget() {
Vertex<String> vertex = new Vertex<String>("a");
vertex.addTarget("b", 5);
vertex.addTarget("c", 3);
assertEquals(0, vertex.removeTarget("d"));
assertEquals(5, vertex.removeTarget("b"));
}