301
社区成员
发帖
与我相关
我的任务
分享别称:结构测试、透明盒测试或基于代码的测试
定义:测试人员需要了解被测试对象的内部逻辑结构、内部特性和源代码,基于这些内部信息来设计测试用例,以检查测试对象的内部结构和代码是否按预期工作
理解:进行白箱测试可得到输入与输出以及测试对象的源代码,需要了解其内部逻辑结构以及内部特性,故除了进行黑箱测试的相同测试外,还可进行依据上述信息针对性地测试,测试其逻辑结构是否正确的
Junit,对不同单元根据JML规格完成断言assert验证
为每一种指令构造其生成函数,lnGen(), apGen()等
为相关指令维护其共享的容器,生成指令时,可从容器中随机选择对象,generatedIds,selectedIds等
为每一种指令设置边界值,每一轮次需保证每一种指令出现次数达到边界值,可保证每条指令出现的频率
可通过设置如下变量设置正确指令(不抛出异常)的概率,通过从指定容器中随机抽取对象,从而保证符合函数的处理要求
private static final int correctCommand = 10;

描述:并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)
作用:并查集的主要作用是求连通分支数
主要构成:
private final HashMap<Integer, Integer> preNodes; private final HashMap<Integer, Integer> rank;前者(
preNodes)记录前驱结点,但经过路径压缩后,同一个连通分支内的所有结点的前驱结点均设置为代表结点(前驱结点为自身),便于判断两个结点是否位于同一个连通分支内。后者(
rank)记录结点的深度(秩),默认根节点(代表结点)的深度为1,用于按秩合并,为降低两个树(以代表元为根结点)合并后得到的树的高度,需要将高度(秩)较低的树的根结点指向高度(秩)较高的树的根结点,并要完成路径压缩。
//添加元素
public void add(int id) {
preNodes.put(id, id);
rank.put(id, 1);
}
//得到其前驱结点,同时实现了路径压缩
public int find(int id) {
int feedback = id;
while (feedback != preNodes.get(feedback)) {
feedback = preNodes.get(feedback);
}
int root = feedback;
int curNode = id;
while (curNode != root) {
int temp = preNodes.get(curNode);
preNodes.replace(curNode, root);
curNode = temp;
if (preNodes.get(curNode) == root) {
break;
}
}
return root;
}
//合成两个连通分支,按秩合并
public void merge(int id1, int id2) {
int root1 = find(id1);
int root2 = find(id2);
if (root1 == root2) {
return;
}
int rank1 = rank.get(root1);
int rank2 = rank.get(root2);
if (rank1 == rank2) {
preNodes.replace(root2, root1);
rank.replace(root1, rank1 + 1);
} else if (rank1 > rank2) {
preNodes.replace(root2, root1);
} else {
preNodes.replace(root1, root2);
}
}
并查集动态表示

MyNetwork类
private final HashMap<Integer, Person> persons;
private int tripleSum;
tripleSum维护this对象中的容器persons内三个Person符合互相满足isLinked状态的个数,需要在MyNetwork调用add_relation,modify_relation时进行维护。
MyPerson类
private final ArrayList<Integer> goodRelSort;
上述容器维护与this对象之间的value递减的MyPerson的id序列,相同value的需维护id较小的在前,需要在MyNetwork调用add_relation,modify_relation时进行维护。
MyTag类
private final HashMap<Integer, Person> persons;
private int ageSum;
private int ageSquareSum;
private int valueSum;
persons储存this对象的所有PersonageSum需要维护persons中的所有Person对象的年龄和ageSquareSum需要维护persons中的所有Person对象的年龄的平方和valueSum需要维护persons中的所有Person对象与this对象之间的value和ageSum和ageSquareSum仅需要在addPerson和delPerson时,进行相应的维护
valueSum 需要在addPerson和delPerson时,根据条件判断是否要更改valueSum,同时在MyNetwork调用add_relation,modify_relation时进行维护(根据实际更新或者删除对象之间的value)
性能问题: 在第二次作业中,未对MyTag类的ValueSum进行维护,单纯根据JML进行双循环遍历,复杂度为$𝑂(𝑛^2)$,导致在往特定的MyTag中加入过多Person后,反复查询其ValueSum,导致超时。
修复情况: 故将ValueSum设置为MyTag的私有属性,通过在addRelation,modifyRelation遍历已有的所有MyTag,依据其内的persons对ValueSum进行维护;除此之外,当在MyTag中删减person时,也需维护ValueSum,从而在查询MyTag的ValueSum时,可直接返回MyTag的属性ValueSum即可,复杂度$O(1)$。
理解: 规格定义方法或系统需要满足的要求,包含限制规则,前置条件,后置条件,副作用范围限定等,但不需要关注实现的方法与过程。
好处:
对验证代码实现与规格的一致性的作用
1. 样例
JUnit测试用例时,由于需要依据规格明确代码的预期行为和输出。故可通过测试用例,验证代码满足与规格的一致性,并且在边界条件和异常情况下是否能够正确处理。JUnit允许独立编写测试,可针对代码的每个部分或功能编写单独的测试用例,从而更精确地验证代码实现与规格的一致性。2. 测试
JUnit提供一套断言方法(如assertTrue(), assertFalse(), assertNull(), assertNotNull()等),故能够通过断言方法验证代码的行为是否符合预期的规格。如果实际输出与预期不符,测试将失败,并给出相应的错误信息,帮助开发者快速定位问题。改进和建议
JML,需要充分阅读并理解相关文档,相当于掌握一门新的”语言“,在实际完成作业时,因为指导书中指出需要根据JML理解本次作业内容,没有给予细致的描述,要充分阅读每一个方法的JML规格,主动联系起来才能理解作业目标。但是在实际编写代码时,只要关注并符合每一个方法的JML规格即可,通过设计合理的架构保证符合规格,降低复杂度(时间或空间,依情况而定)github进行分享,收到使用者的赞扬,在开发过程中,需要保证迭代的连续性,并尽可能便于使用者理解与使用。Junit测试时,使用上述评测机的数据生成器产生测试样例,能自行调节测试样例的规模与指令比例,极大提高覆盖率。编写方法的测试代码时,需注重是否验证pure特性,并关注通过方法得到的容器属性是深拷贝还是浅拷贝,若是浅拷贝则需要new一个相同的对象便于进行方法执行前后的比对。JML导致的理解偏差以及其本身的不易读性,还是不错的