301
社区成员
发帖
与我相关
我的任务
分享黑箱测试是在完全不考虑程序内部结构和内部特性的情况下测试程序是否能完成应具有的功能的测试。
特点
不需要了解程序内部的代码以及实现
通过对比输入输出检查功能是否正确实现
根据功能要求进行数据构造
不可能覆盖所有代码,覆盖率较低
测试方法
等价类划分法;边界值分析法;因果图法;场景法;正交实验设计法;判定表驱动分析法;错误推测法;功能图分析法......
白盒测试又称为结构测试或逻辑驱动测试,它是把测试对象看成一个透明的盒子,允许测试人员利用程序内部的逻辑结构设计测试用例,对程序所有逻辑路径进行测试。
特点
与黑箱测试不同,测试对象是代码
需要测试人员了解程序的内部逻辑
保证所有独立路径至少被测试一次
测试方法
语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖和路径覆盖......
单元测试是对软件组成单元进行测试,检验软件基本组成单位的正确性,又称为模块测试。
特点
通常由开发人员编写
通常在编码后进行,可为后期维护代码降低代价
功能测试是在规定的一段时间内运行软件系统的所有功能,测试软件的功能是否符合需求。
特点
通常采用黑盒测试方法
一般由测试人员独立执行
集成测试也称组装测试,将程序模块采用适当的集成策略组装起来,对系统的接口及集成后的功能进行正确性检测的测试工作,其主要目的是检查软件单位之间的接口是否正确。
特点
一般在单元测试之后进行
重点关注数据传递是否正确
压力测试用于验证软件应用程序的稳定性和可靠性,其目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力,并确保软件在危急情况下不会崩溃,可测试超出正常工作数据点,评估软件在极端条件下的工作情况。
特点
一直进行到系统故障为止
尝试通过模拟大量用户和匮乏的资源等极端情况破坏系统
回归测试是指在软件项目中,开发人员在修改了软件的代码以修复已经发现的bug后,测试人员在需要重新测试前面已经测试过的内容,以确认此次修改没有引入新的错误。
特点
分为完全回归和部分回归
需要专门人员进行实施,从业务流驱动、数据与用例分离、统一的平台等多维度出发进行长期建设。
在这单元的数据构造中,我采取了以随机数据为主特殊数据为辅的构造方法。首先要关注有什么方法会影响测试对象,针对这些方法构造随机数据,保证随机数据的范围符合题目要求并覆盖各种情况。除此之外,一些特殊情况,如完全图等就需要额外构造特殊数据点来保证程序在极端情况不会出错。
hw9中的重点主要在于如何构建图,我选择在每个Person中用Hashmap记录下他链接的人,在dfs等算法中都通过查询该点的Hashmap来遍历图,并未在network中用别的数据结构来记录整个图。所以为了降低时间复杂度只能用路径压缩的并查集和动态维护(在合并并查集和拆分并查集时改变blocks的数值)等方法。
hw10中主要添加了新的类MyTag,我也采用了Hashmap来记录tag,其中的queryBestAcquaintance()方法不优化的话复杂度会达到O(n^2),于是我用大顶堆来保证快速查询所连接的value最大的person。
this.maxHeap = new PriorityQueue<>((p1, p2) -> {
if (p1.getValue() == p2.getValue()) {
return Integer.compare(p1.getId(), p2.getId()); // 若value相同,按id升序
}
return Integer.compare(p2.getValue(), p1.getValue()); // 按value降序
});
public int getBestAc() {
int a = maxHeap.peek().getId();
return a;
}
hw11中添加了MyMessage类和三种不同的message类,严格按照JML书写即可,没有什么复杂度较高的方法。在Network中我仍然采取了Hashmap数据类型来记录message有关的信息。
我在hw9和hw10中都出现了性能问题,主要通过用更高效的数据结构和算法来解决。
hw9
在hw9中,我一开始未考虑到queryTripleSum()等方法容易出现TLE的情况,导致在强测狠狠t了一把。
在修bug的过程中,对于查询指令,我采取了动态维护的方法,只在mr和ar的时候维护即可。
public void manageTriple(int id1, int id2) {
for (int id : persons.keySet()) {
if (id == id1 || id == id2) { continue; }
if (persons.get(id).isLinked(getPerson(id1))
&& persons.get(id).isLinked(getPerson(id2))) {
trisum++;
}
}
}
public void deletTriple(int id1, int id2) {
for (int id : persons.keySet()) {
if (id == id1 || id == id2) { continue; }
if (persons.get(id).isLinked(getPerson(id1))
&& persons.get(id).isLinked(getPerson(id2))) {
trisum--;
}
}
}
对于isCircle()方法,我采取了路径压缩的并查集算法,但由于mr时会有因为value值小于0而被删除的边,此时需要通过dfs来检查是否有并查集一分为二,若没有则不需要改动,若有则需要把目前集合数加一,并分别改动与A点和B点相连的点的父亲为A点、B点。
public int merge(int id1, int id2) {
int father1 = find(id1);
int father2 = find(id2);
if (father1 == father2) {
return -1;
}
int rank1 = rank.get(father1);
int rank2 = rank.get(father2);
if (rank1 < rank2) {
fa.put(father1, father2);
}
else {
if (rank1 == rank2) {
rank.put(father1, rank1 + 1);
}
fa.put(father2, father1);
}
return 0;
}
hw10
对于hw10,我在强测TLE了一个点,原因是未考虑到大量qtvs指令的极端情况,qtvs方法的时间复杂度过高,对此也采取动态维护的方法来解决。我在Myperson中增加了一个Hashmap来记录该Person存在于哪个tag中,并在ar,mr,att等方法中修改该Hashmap,其目的是在mr改变value值时对所有包含改变的两个Person的Tag中的valueSum进行修改。
public void addIntags(int id, int tagId) {
if (intags.containsKey(id)) {
ArrayList<Integer> a = intags.get(id);
a.add(tagId);
} else {
ArrayList<Integer> a = new ArrayList<>();
a.add(tagId);
intags.put(id, a);
}
}
我的Junit测试主要分为构造数据和验证结果正确性这两部分。对于构造数据,我主要采用随机数的构造方法,随机构造与测试方法有关的指令并执行,得到与实际情况相似的数据。
随后执行测试方法,在hw9和hw10中,我在Junit中计算了正确方法的执行结果,对比俩个结果来判断测试方法的正确性。在hw11中,我采取了根据JML中的ensure语句来一条一条判断测试结果是否符合要求。
在这单元的作业中,仔细阅读并理解JML、选择合适的算法和数据结构去防止TLE是至关重要的。我在这单元的强测中出现了大量错误,这都是由于没有事先考虑好时间复杂度上的问题,总是想当然觉得查询指令不会太多不会TLE, 在第十一周的作业中还因为自己图方便曲解了JML的意思导致了bug。我应该在阅读完JML中考虑清楚哪些方法复杂度较高容易tle,出了在时间复杂度上的优化以外其余的内容尽量严格按照JML来写,可以通过书写Junit测试的方法来测试JML的实现是否正确。