BUAA OO Unit JML

符悦-21231042 学生 2024-05-16 15:23:43

测试

本单元要求使用JUnit进行测试,并且需要在中测中用JUnit对课程组的代码进行测试,并hack掉错误的代码

由于测试中需要自己构造数据,应该有很多同学手工捏造了很多边界数据来hack课程组代码,但是实际上在实践中发现,纯粹随机产生的数据是完全可以测试出课程组的代码错误的力大砖飞

如果你的数据没有成功,那一定是你的组数不够

我所写的测试大概是以下结构

// generate random dataset
prepareData();

// calculate std
var std = calculateStd(stdNetwork);

// check for problem
assertEqual(std, testNetwork.someOperation());

其中

  • 产生随机数据时会构建两个完全一样的network,一个作为std,一个用作test。
  • 计算std的函数在JUnit对象中实现
  • 断言的过程严格按照JML的要求

测试中我设计了一个基类用来构造数据,其子类中实现具体的单元测试

黑箱、白箱

  • 黑箱测试:也称为功能测试,测试人员在不知道程序内部结构和实现细节的情况下,根据软件的功能规格说明书和用户需求来设计测试用例,验证软件系统的功能是否符合预期。其目的是从用户的角度验证软件的输入和输出是否正确,确保软件在各种条件下都能正常工作。

    JUnit

  • 白箱测试:也称为结构测试或透明盒测试,测试人员需要了解软件内部的代码结构和实现细节。通过对程序内部逻辑、代码路径、条件分支等进行测试,确保软件内部操作按预期进行,且代码覆盖率高,从而提高软件质量和可靠性。

    互测

各种测试

  • 单元测试:单元测试旨在验证软件系统中的最小可测试单元(通常是函数、方法或类)的正确性。单元测试的目的是确保每个单元独立工作,按照预期执行,并返回正确的结果。(JUnit)
  • 功能测试:功能测试(黑箱)旨在验证软件系统的各个功能模块是否按照需求规格说明书的要求正常工作。功能测试关注的是软件的功能行为,而不涉及其内部实现。其目标是确保软件的每个功能都能够正确地响应各种输入并产生预期的输出。(中测)
  • 集成测试:旨在验证不同模块或组件之间的交互和集成是否正常工作。集成测试的目标是确保各个模块在组合后能够协同工作,正确地完成预期的功能。(中测)
  • 压力测试:强测
  • 回归测试:旨在验证在软件修改、更新或升级之后,原有功能是否仍然正常工作,确保新代码没有引入新的缺陷或破坏现有功能。回归测试通常在修复缺陷、添加新功能或进行代码优化后进行。(Bug修复)

架构

img

架构就是按照JML规格实现的,其实没什么特别值得讲的

Network中包含了一个并查集,其他绝大部分的数值都是动态维护的。

本单元绝大部分的性能要求都可以通过动态维护满足

大部分携带Id域的数据都通过hashmap维护,Person中的acquaintance由PersonNode维护Person和Value

private final HashMap<Integer, PersonNode> acquaintance;

public class PersonNode {
    private final Person person;
    private final int value;

    public PersonNode(Person person, int value) {
        this.person = person;
        this.value = value;
    }

    public Person getPerson() {
        return person;
    }

    public int getValue() {
        return value;
    }
}

性能

正如前面所说,绝大多数的性能问题都可以通过动态维护解决

public T getValue() {
    if (resetValue) {
        this.value = calculateValue();
    }
    
    return value;
}

可达性问题通过并查集解决,大部分同学都是这样处理的,没有叙述的必要

对于最短路径,我采用了Dijkstra算法

PriorityQueue<Path> queue
                = new PriorityQueue<>(Comparator.comparing(Path::getValue));
        HashSet<Integer> visited = new HashSet<>();
        Path current = new Path(id1, id1, 0);
        while (current.getTo() != id2) {
            for (PersonNode personNode
                    : ((MyPerson) getPerson(current.getTo()))
                    .getAcquaintance().values()) {
                MyPerson person = (MyPerson) personNode.getPerson();
                if (visited.contains(person.getId())) {
                    continue;
                }
                queue.add(new Path(id1, person.getId(), current.getValue() + 1));
                visited.add(person.getId());
            }

            current = queue.poll();
        }

        return current.getValue() - 1;

规格实现分离

按照规格的写既不好维护又慢

规格和JUnit

正如在测试部分所说,断言部分严格按照JML的描述来实现,一定程度上简化了书写测试的难度

然而,我相信写JML的人极度的痛苦,所以这不过是把问题从一个部分移到了另一个部分

JML在绝大部分情况下都是这样的,本质上把实现的困难放到了书写JML的过程里,没有什么意义

体会

JML真没什么用,看的痛苦,恐怕写的也痛苦,建议删了,没有什么自然语言描述不了的情况

...全文
40 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧