301
社区成员
发帖
与我相关
我的任务
分享黑箱测试是基于软件需求和功能规格的测试方法。测试人员不需要了解内部代码或结构,只需要通过输入合法和非法的输入数据,检查系统的输出是否符合预期即可。黑箱测试强调对系统功能、接口、性能和安全等方面进行测试,而不关心内部实现。优点:独立于内部代码实现,侧重于用户需求和期望。缺点:无法发现代码中的逻辑错误和编程错误,只能通过输入和输出来验证系统行为。
白箱测试是基于内部代码和结构的测试方法,也称为结构化测试。测试人员根据代码的逻辑路径和结构设计测试用例,覆盖不同的代码分支和条件。白箱测试重点是验证程序的内部逻辑是否正确,例如语句覆盖、分支覆盖、路径覆盖等。优点:能够发现代码中的逻辑错误和编程错误,提高代码质量。缺点:测试人员需要了解代码实现细节,测试过程相对较复杂。
单元测试是针对程序中最小的可测试单元进行的测试,如函数、方法或类。测试人员编写测试用例,验证单元的功能是否按预期工作。单元测试旨在隔离和测试每个单元,确保其功能的正确性。
功能测试是验证软件系统是否满足需求规格说明书中描述的功能。测试人员根据需求规格书编写测试用例,测试系统的各个功能是否按照规定工作。功能测试重点在于确认系统的功能是否正常。
集成测试是测试多个模块组合在一起后的整体系统功能。测试人员逐步将各个模块集成起来,测试模块之间的接口和交互。集成测试旨在确保各个模块之间的协作正确,整个系统的功能正常。
压力测试是测试系统在异常条件下的负载能力。测试人员通过模拟大量用户访问、大数据量处理等情况,测试系统的性能和稳定性。压力测试旨在确定系统在高负载条件下的性能极限和稳定性。
回归测试是对已经修改过的软件进行重新测试,以确保修改不会影响到原有功能的正确性。测试人员在每次软件发生变更后,重新运行之前的测试用例,验证修改的部分是否正常,同时不影响其他功能。回归测试旨在保证软件的稳定性和可靠性,在软件修改后进行验证。
下面以dce为例,解释使用JUnit进行测试的具体步骤:
1.首先利用random随机生成一定人数的Person(若id相同则重新生成)
2.在Person中随机选取一个Person,在Person的关系中随机选取一个人,从而生成二者之间的关系(如果二者之间已经存在关系则改为修改关系)
3.随机存储一些表情
4.在Person中随机选取一个Person,在Person的关系中随机选取一个人,生成要发送的表情Message并发送,从而对不同的表情生成不同的热度
5.随机生成三种不同类型的Message
6.在0-Emoji的最高热度之间随机选取一值作为limit,以其为下限删除表情,最后通过如下assert及衍生方法检验删除表情之后的表情序列和消息序列是否满足正确的要求
assertEquals(myNetwork.deleteColdEmoji(limit),newEmojiHeats.length);
for (Message message : messages) {
if (message instanceof EmojiMessage && emojis.get(((EmojiMessage) message).getEmojiId()) < limit) {
assertFalse(messageHashMap.containsKey(message.getId()));
} else {
assertTrue(messageHashMap.containsKey(message.getId()));
}
}
assertEquals(newEmojiIds.length,newEmojiHeats.length);
for (int i = 0;i < newEmojiIds.length;i++) {
assertTrue(newEmojiHeats[i] >= limit);
assertTrue(emojis.containsKey(newEmojiIds[i]);
assertEquals(emojiHeats[i], (int) emojis.get(emojiIds[i]));
}
在第九次作业中,一共有Main、MyPerson、MyNetwork三个类和四个异常处理类,第十次作业增加了MyTag类和四个异常处理类,第十一次作业增加了MyNetwork2类以应对一个类中代码行数超过500行的问题,也增加了Message、EmojiMessage、NoticeMessage、RedEnvolopeMessage三个类和四个新的异常处理类。
在MyNetwork、MyPerson、MyTag中继承了各自父类JML规定的所有方法,在MyPerson中额外增加了一些修改和获得Parent的方法,用以计算和维护并查集,在MyNetwork2类中有modify1和modify2两个方法,用于具体的修改关系方法的实现,同时还有dfs方法,用于深度优先遍历算法的实现。
以下是方法复杂度:
| method | CogC | ev(G) | iv(G) | v(G) |
| Main.main(String[]) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyAcquaintanceNotFoundException.MyAcquaintanceNotFoundException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyAcquaintanceNotFoundException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEmojiIdNotFoundException.MyEmojiIdNotFoundException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyEmojiIdNotFoundException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEmojiMessage.getEmojiId() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEmojiMessage.MyEmojiMessage(int, int, Person, Person) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEmojiMessage.MyEmojiMessage(int, int, Person, Tag) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEqualEmojiIdException.MyEqualEmojiIdException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyEqualEmojiIdException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEqualMessageIdException.MyEqualMessageIdException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyEqualMessageIdException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEqualPersonIdException.MyEqualPersonIdException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyEqualPersonIdException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyEqualRelationException.MyEqualRelationException(int, int) | 5.0 | 1.0 | 4.0 | 4.0 |
| MyEqualRelationException.print() | 2.0 | 1.0 | 2.0 | 2.0 |
| MyEqualTagIdException.MyEqualTagIdException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyEqualTagIdException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.equals(Object) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyMessage.getId() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.getPerson1() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.getPerson2() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.getSocialValue() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.getTag() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.getType() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.MyMessage(int, int, Person, Person) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessage.MyMessage(int, int, Person, Tag) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyMessageIdNotFoundException.MyMessageIdNotFoundException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyMessageIdNotFoundException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.addMessage(Message) | 6.0 | 4.0 | 6.0 | 6.0 |
| MyNetwork.addPerson(Person) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyNetwork.addPersonToTag(int, int, int) | 7.0 | 7.0 | 8.0 | 8.0 |
| MyNetwork.addRelation(int, int, int) | 17.0 | 4.0 | 11.0 | 12.0 |
| MyNetwork.addTag(int, Tag) | 3.0 | 3.0 | 3.0 | 3.0 |
| MyNetwork.clearNotices(int) | 7.0 | 2.0 | 4.0 | 4.0 |
| MyNetwork.containsEmojiId(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.containsMessage(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.containsPerson(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.deleteColdEmoji(int) | 8.0 | 1.0 | 7.0 | 7.0 |
| MyNetwork.delPersonFromTag(int, int, int) | 5.0 | 5.0 | 5.0 | 5.0 |
| MyNetwork.delTag(int, int) | 3.0 | 3.0 | 3.0 | 3.0 |
| MyNetwork.getEmojiHeatList() | 1.0 | 1.0 | 1.0 | 2.0 |
| MyNetwork.getEmojiIdList() | 1.0 | 1.0 | 1.0 | 2.0 |
| MyNetwork.getMessage(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.getMessages() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.getPerson(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.isCircle(int, int) | 3.0 | 3.0 | 3.0 | 3.0 |
| MyNetwork.modifyRelation(int, int, int) | 11.0 | 5.0 | 7.0 | 8.0 |
| MyNetwork.MyNetwork() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.queryBestAcquaintance(int) | 3.0 | 3.0 | 3.0 | 3.0 |
| MyNetwork.queryBlockSum() | 3.0 | 1.0 | 2.0 | 3.0 |
| MyNetwork.queryCoupleSum() | 6.0 | 1.0 | 3.0 | 4.0 |
| MyNetwork.queryMoney(int) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyNetwork.queryPopularity(int) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyNetwork.queryReceivedMessages(int) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyNetwork.queryShortestPath(int, int) | 28.0 | 8.0 | 7.0 | 15.0 |
| MyNetwork.querySocialValue(int) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyNetwork.queryTagAgeVar(int, int) | 3.0 | 3.0 | 3.0 | 3.0 |
| MyNetwork.queryTagValueSum(int, int) | 6.0 | 4.0 | 3.0 | 8.0 |
| MyNetwork.queryTripleSum() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNetwork.queryValue(int, int) | 4.0 | 4.0 | 4.0 | 4.0 |
| MyNetwork.sendMessage(int) | 22.0 | 4.0 | 16.0 | 16.0 |
| MyNetwork.storeEmojiId(int) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyNetwork2.dfs(int, HashSet, HashMap) | 4.0 | 1.0 | 3.0 | 3.0 |
| MyNetwork2.modify1(int, int, int, HashMap) | 29.0 | 1.0 | 18.0 | 18.0 |
| MyNetwork2.modify2(int, int, HashMap) | 26.0 | 1.0 | 17.0 | 17.0 |
| MyNetworkTest.TestDeleteColdEmoji() | 63.0 | 4.0 | 26.0 | 29.0 |
| MyNoticeMessage.getString() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNoticeMessage.MyNoticeMessage(int, String, Person, Person) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyNoticeMessage.MyNoticeMessage(int, String, Person, Tag) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPathNotFoundException.MyPathNotFoundException(int, int) | 4.0 | 1.0 | 3.0 | 3.0 |
| MyPathNotFoundException.print() | 2.0 | 1.0 | 2.0 | 2.0 |
| MyPerson.addMoney(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.addSocialValue(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.addTag(Tag) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.containsTag(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.delTag(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.equals(Object) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyPerson.getAcquaintance() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getAge() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getBestAcquaintance() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getBestAcquaintanceValue() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getId() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getMessages() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getMoney() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getParent() | 2.0 | 2.0 | 2.0 | 2.0 |
| MyPerson.getReceivedMessages() | 4.0 | 1.0 | 3.0 | 3.0 |
| MyPerson.getSocialValue() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getTag(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getTags() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.getValue() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.isLinked(Person) | 1.0 | 1.0 | 2.0 | 2.0 |
| MyPerson.MyPerson(int, String, int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.queryValue(Person) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyPerson.setBestAcquaintance(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.setBestAcquaintanceValue(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.setMessages(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.setMoney(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.setParent(MyPerson) | 3.0 | 1.0 | 3.0 | 3.0 |
| MyPerson.setParentOnly(MyPerson) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPerson.setSocialValue(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyPersonIdNotFoundException.MyPersonIdNotFoundException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyPersonIdNotFoundException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyRedEnvelopeMessage.getMoney() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyRedEnvelopeMessage.MyRedEnvelopeMessage(int, int, Person, Person) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyRedEnvelopeMessage.MyRedEnvelopeMessage(int, int, Person, Tag) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyRelationNotFoundException.MyRelationNotFoundException(int, int) | 4.0 | 1.0 | 3.0 | 3.0 |
| MyRelationNotFoundException.print() | 2.0 | 1.0 | 2.0 | 2.0 |
| MyTag.addPerson(Person) | 1.0 | 1.0 | 2.0 | 2.0 |
| MyTag.delPerson(Person) | 5.0 | 1.0 | 4.0 | 4.0 |
| MyTag.equals(Object) | 2.0 | 2.0 | 2.0 | 2.0 |
| MyTag.getAgeMean() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyTag.getAgeVar() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyTag.getId() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyTag.getPersons() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyTag.getSize() | 0.0 | 1.0 | 1.0 | 1.0 |
| MyTag.getValueSum() | 6.0 | 1.0 | 4.0 | 4.0 |
| MyTag.hasPerson(Person) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyTag.MyTag(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| MyTagIdNotFoundException.MyTagIdNotFoundException(int) | 2.0 | 1.0 | 2.0 | 2.0 |
| MyTagIdNotFoundException.print() | 0.0 | 1.0 | 1.0 | 1.0 |
| Total | 348.0 | 183.0 | 304.0 | 326.0 |
| Average | 2.8524590163934427 | 1.5 | 2.4918032786885247 |
2.6721311475409837 |
可以看出,JUnit测试中的TestDeleteColdEmoji方法,MyNetwork中的sendMessage和addRelation方法的复杂度较高。
以下是类复杂度:
| class | OCavg | OCmax | WMC |
| MyEmojiIdNotFoundException | 1.5 | 2.0 | 3.0 |
| MyEmojiMessage | 1.0 | 1.0 | 3.0 |
| MyEqualEmojiIdException | 1.5 | 2.0 | 3.0 |
| MyEqualMessageIdException | 1.5 | 2.0 | 3.0 |
| MyEqualPersonIdException | 1.5 | 2.0 | 3.0 |
| MyEqualRelationException | 3.0 | 4.0 | 6.0 |
| MyEqualTagIdException | 1.5 | 2.0 | 3.0 |
| MyMessage | 1.1111111111111112 | 2.0 | 10.0 |
| MyMessageIdNotFoundException | 1.5 | 2.0 | 3.0 |
| MyNetwork | 3.5294117647058822 | 12.0 | 120.0 |
| MyNetwork2 | 8.666666666666666 | 13.0 | 26.0 |
| MyNetworkTest | 25.0 | 25.0 | 25.0 |
| MyNoticeMessage | 1.0 | 1.0 | 3.0 |
| MyPathNotFoundException | 2.5 | 3.0 | 5.0 |
| MyPerson | 1.2 | 3.0 | 36.0 |
| MyPersonIdNotFoundException | 1.5 | 2.0 | 3.0 |
| MyRedEnvelopeMessage | 1.0 | 1.0 | 3.0 |
| MyRelationNotFoundException | 2.5 | 3.0 | 5.0 |
| MyTag | 1.7272727272727273 | 4.0 | 19.0 |
| MyTagIdNotFoundException | 1.5 | 2.0 | 3.0 |
| Total | 289.0 | ||
| Average | 2.3688524590163933 | 4.136363636363637 | 13.136363636363637 |
qci是查询两个Person是否在同一个连通子图中,通过并查集实现。初始时,将每个节点的父节点设为自身,如果两个节点要建立联系,则将其中一个节点的父节点设为另一个节点的父节点。同时,在查询和设置节点的时候,采取路径压缩的办法以降低查询时的时间开销。如果两个点之间的边需要删除,则在删边前后对某一个节点进行深度优先搜索(DFS),把第二次DFS的结果的父节点设为该节点,把第一次DFS结果中有而第二次DFS的结果中没有的节点的父节点设为另一个节点。在qci中,如果两个节点的父节点相同,则返回true,否则返回false;在qbs中,返回父节点为自身的节点数之和。
qts主要是通过在ar和mr时进行维护。在ar和mr时,遍历两个人的关系,如果其中有两个人共有的关系,则加上或减去共有的朋友的数量
qtvs可以在ar和mr的时候进行维护,但问题在于维护时需要遍历所有Tag里面的所有Person,也可以在查询时进行检索。为了提高查询的效率,可以使用cache。
当ar或mr的value大于0时,查询此时最好朋友的关系值是否大于新的关系值;当value小于0时,遍历此人的所有关系找到此时的最好朋友,为了降低时间开销,可以采用大顶堆的优先队列完成。qcs可以在修改最好朋友的时候同步修改,也可以进行遍历。(注意不能使用二重循环,将导致时间复杂度达到O(N^2)。)
采用广度优先搜索(BFS),同时使用cache,加快效率。