301
社区成员
发帖
与我相关
我的任务
分享黑箱测试是软件测试中的一种方法,它通过在不考虑程序内部结构的情况下,根据程序的需求和规格进行测试。这意味着测试人员不需要了解程序的内部代码或设计,而是关注程序的输入和输出,以验证程序是否按照预期工作。
在黑箱测试中,测试人员通常依据需求规格、用户文档或其他可用的文档,设计测试用例并执行测试。测试用例涵盖了各种情况,包括正常情况下的输入、边界情况、异常情况等,以确保程序在各种情况下都能正确地运行。
黑箱测试的优点之一是它与具体的编程语言或技术无关,因此测试人员不需要具备特定的编程技能。然而,它也有一些局限性,例如无法发现程序内部的逻辑错误或代码缺陷。
总的来说,黑箱测试在软件开发过程中扮演着重要的角色,帮助确保软件符合用户需求并具有良好的功能性。
白箱测试是软件测试中的另一种方法,与黑箱测试相对。白箱测试也被称为结构测试或透明盒测试,它关注的是测试软件的内部结构、逻辑和代码。
在白箱测试中,测试人员会深入了解软件的内部工作原理,包括代码逻辑、数据结构、变量和函数等。然后,测试人员设计测试用例,以验证代码是否按照设计规范和预期进行了实现。白箱测试通常涵盖的内容包括路径覆盖、语句覆盖、分支覆盖等,以确保代码的每个部分都被有效地测试到。
与黑箱测试相比,白箱测试的优点之一是可以更深入地检查软件的内部逻辑,发现潜在的编程错误和缺陷。然而,它也需要测试人员具备更深的技术和编程知识,并且可能受到代码变更的影响。
总的来说,白箱测试和黑箱测试通常结合使用,以确保软件在功能和结构上都达到高质量的标准。
单元测试是软件开发中的一种测试方法,用于验证程序中最小可测试单元的功能是否按照预期工作。这些最小可测试单元通常是函数、方法或类等代码片段。单元测试的目的是在开发过程中尽早地发现和修复代码中的错误,以确保每个单元都能独立地、正确地运行。
功能测试是软件测试的一种类型,它旨在验证软件的各项功能是否按照需求和规格说明正常工作。功能测试关注的是软件的外部行为,而不涉及其内部实现细节。
集成测试是软件测试中的一种测试方法,其主要目的是验证不同软件模块之间的交互和集成是否正常工作。在软件开发过程中,通常会将各个模块独立开发和测试,而集成测试则是在将这些模块组装在一起后进行的测试。
压力测试是软件测试的一种类型,旨在评估系统在正常或极限负载下的性能表现。它通常用于确定系统在各种条件下的稳定性和可靠性,以及在达到或超过预期负载时的表现情况。
回归测试是软件测试中的一种测试方法,其主要目的是确保对软件进行更改或修复后,已有的功能仍然能够正常运行,不会因为新的更改而引入新的错误或破坏已有的功能。回归测试旨在验证软件的稳定性和一致性,以确保对软件的修改不会对现有功能产生负面影响。
数据构造采用了全随机的办法,主要是使用java自带的Random类,比如一个图中的人数设置为100-200个人可以采用如下语句。
int peoplenumber = random.nextInt(100);
for (int i = 0;i < peoplenumber + 100;i++) { // 随机添加100-200个人
Person person = new MyPerson(i,String.valueOf(i), random.nextInt(200));
if (!net.containsPerson(i)) {
try {
net.addPerson(person);
} catch (EqualPersonIdException e) {
throw new RuntimeException(e);
}
}
}
然后两个人之间有没有关系也采用随机的方法。
for (int i = 0;i < peoplenumber - 1;i++) {
for (int j = i + 1;j < peoplenumber;j++) {
if (random.nextBo0lean()) {
try {
net.addRelation(i,j,random.nextInt(200));
} catch (PersonIdNotFoundException e) {
throw new RuntimeException(e);
} catch (EqualRelationException e) {
throw new RuntimeException(e);
}
}
}
}
这样就自然而然的生成了一个完全随机的图,这个图基本上能满足本次测试方法的要求。
本次作业我主要是采用了hashMap的容器,以ID作为key以类作为value,因为这样可以很好的根据ID取自己想要的值。使时间复杂度为O(1),而不是遍历一遍取想要的值的O(n)。架构与JML的要求基本一样。在此就不继续介绍了。
本次作业我采用了许多动态维护策略,比如tripleSum,会在每次加边或者修改边的时候遍历维护一遍
for (Integer key : persons.keySet()) {
if (key != id1 && key != id2 && persons.get(key).isLinked(persons.get(id1)) &&
persons.get(key).isLinked(persons.get(id2))) {
tripleNum--;
}
}
这个时间复杂度为O(n),是可以接受的,如果采用三循环遍历的方法时间复杂度为n的立方,这样就会造成反复调用这个方法的时候出现ctle
还有blockSum,iscircle的获取,我也是采用动态维护的方法,我主要使用了并查集的算法,这样在调用方法的时候就可以直接返回维护好了的数据,而不是递归或者循环,会浪费大量时间。
还有coupleSum的维护,我的维护将时间复杂度将为了O(常数),我认为还是写的比较妙的一个方法。
private void UpDateCoupleNum(int id1,int id2,int beforeOrAfter) {
int bst1 = ((MyPerson)persons.get(id1)).BestId();
int bst2 = ((MyPerson)persons.get(id2)).BestId();
if (!((MyPerson)persons.get(id1)).Empty() &&
((MyPerson)persons.get(bst1)).BestId() == id1) {
coupleNum += beforeOrAfter;
}
if (!((MyPerson)persons.get(id2)).Empty() &&
((MyPerson)persons.get(bst2)).BestId() == id2) {
coupleNum += beforeOrAfter;
}
if (bst1 == id2 && bst2 == id1) {
coupleNum -= beforeOrAfter;
}
}
·····
UpDateCoupleNum(id1,id2,-1);
((MyPerson)persons.get(id1)).ModifyLink(persons.get(id2),value);
((MyPerson)persons.get(id2)).ModifyLink(persons.get(id1),value);
UpDateCoupleNum(id1,id2,1);
·····
这个UpdateCoupleSum方法只需要在修改前和后调用一下就可以动态维护CoupleSum了,且时间复杂度为O(常数),成本很低。
另外还有BestAcquaintance,valueSUm,ageVar等采用了动态维护等方式,这里就不一一赘述了。
一开始我并没有使用动态维护的方法,而是根据JML老老实实的翻译它给的代码,导致整体跑的特别慢,出现了许许多多的性能问题。之后我把能维护的量全部改为动态维护,这样一来就没有再出现超时的情况了。
还有一个小bug就是Integer类不可以使用==比较,而是要用.equals,因为==表示的是这两个变量指向同一个类,而不同类但是数值相等可能也不满足==,所以在一些情况下会出现判断错误的情况,我在一些极端情况下就出现了这种情况。
本单元要求我们实现某些方法的Junit测试,我的做法是先随机生成一些数据以用以测试,然后根据JML用最简单的方法得出要测试方法的结果,然后将这个结果与调用的方法进行比较,另外,还要保证ensures的所有内容我的test中都有涉及,这样,我的test才是完美的。
学习JML规格是对软件开发中的一种新思路和方法的探索。JML规格作为一种形式化的规约语言,可以帮助我们更清晰地定义软件系统的行为和约束,从而提高代码的可靠性和可维护性。
通过学习JML规格,我深刻体会到了规范在软件开发中的重要性。通过在代码中嵌入JML规约,我们可以明确地定义函数和类的前置条件、后置条件和类不变式,使得代码的行为更加可预测和可控。这有助于开发人员更好地理解代码的预期行为,并在开发过程中进行验证和测试,从而减少错误和提高代码质量。
另外,学习JML规格也让我意识到了规约驱动设计的思想。通过在设计阶段就明确定义系统的规约和约束,我们可以更加系统地进行软件设计,从而减少后续开发中的迭代和修改。这有助于加快开发周期、降低维护成本,并提高系统的可维护性和可扩展性。
总的来说,学习JML规格是我在软件开发领域的一次新的探索和尝试。我相信通过不断学习和实践,我可以更加熟练地运用JML规格来提高自己的软件开发能力,并为构建高质量的软件系统贡献自己的一份力量。