BUAA_2025_OO_Unit3单元总结

程嘉烨-23373532 2025-05-19 18:00:36

一、测试过程分析与测试策略

1. 测试体系分层实践
在本单元的作业中,我们构建了多层次测试体系:
• 单元测试:针对每个JML规格方法编写独立测试用例,同时包装addPerson、addRelation等原子操作

• 功能测试:只需考虑需要方法的功能,不需要考虑内部结构及代码。

  @Test
//验证pure
  public void testPureProperty() throws Exception {
      Network network = createSampleNetwork();
      // 记录初始状态
      PersonInterface[] before = network.getPersons();
      // 调用方法
      network.queryCoupleSum();
      // 验证状态未改变
      PersonInterface[] after = network.getPersons();
      assertArrayEquals("Data modified after pure method call", before, after);
  }

• 集成测试:验证模块间协作。在本单元中,我们有时需要对一些值进行维护,以加快查找速度,以queryTagValueSum方法为例,构建跨标签的关系网络,测试添加/删除人员时多个标签的数值同步更新逻辑

• 压力测试:通过自动化脚本生成超大规模数据测试程序的性能和正确性,包括可能的tle以及wa

• 回归测试:每次迭代后运行历史测试集,我在测试时候并未采用该方法

2. 数据构造策略

白箱+黑箱(AI)策略提升测试覆盖率:

  • 白箱
  • 基础场景
    构造基础特征数据组合,如:
    // 五种图结构
    EMPTY_GRAPH, SINGLE_NODE, TWO_NODES, TRIANGLE, COMPLEX_GRAPH
    
  • 边界值构造
    重点关注空图、完全图、最大节点数等边界场景:
    // 测试网络容量边界
    for (int i=0; i<MAX_PERSON; i++) {
        network.addPerson(new Person(i, "Test", 20));
    }
    
  • 黑箱
  • 随机化测试
    开发自动化数据生成工具,数据构造器来随机生成数据

二、大模型辅助开发实践

JML规格解析
本单元大模型在写代码过程中最大的作用是读取jml信息并以自然语言描述出来辅助我们的理解,加快jml阅读速度

[用户输入]  
解释JML中的ensures子句:  
@ ensures \result == (\sum int i; 0<=i<people.length; people[i].getAge());

[模型输出]
该规格要求方法返回值等于people数组中所有人员年龄的总和

但是往往直接将jml以及作业要求喂给AI,其写出来的方法很容易出现tle或者wrong answer
同样的,在ai给出的代码基础上自己进行修改工作量大,对于条件容易遗漏

三、图模型构建与优化

img

在本单元中,社交网络可以抽象为一个无向图,其中人员表示为图中的节点,人员之间的关系表示为图中的边,边的权重表示关系的数值。具体实现时,使用 Network 类中的 persons 列表来存储所有的人员节点,每个 Person 类实例中使用 acquaintance 数组和 value 数组来存储其相邻节点和对应的边权重。

图模型维护
  • 添加人员:当调用 Network 类的 addPerson 方法时,会检查人员 ID 的唯一性
  • 添加关系:当调用 Network 类的 addRelation 方法时,会检查两个人员是否存在以及关系是否已经存在。如果人员存在且关系不存在,则在两个人员的 acquaintance 数组和 value 数组中添加相应的信息。
  • 修改关系:当调用 Network 类的 modifyRelation 方法时,会检查两个人员是否存在、关系是否存在以及修改后的权重是否大于 0。如果满足条件,则更新关系的权重;如果权重小于等于 0,则删除该关系,并从相关标签中移除对应的人员。

存储person时我采用的是

private final ArrayList<Person> persons = new ArrayList<>();

但是性能不佳 可以采用邻接表+哈希索引:

private Map<Integer, Person> personMap = new HashMap<>();
private Map<Integer, List<Edge>> adjacencyList = new HashMap<>();

四、性能问题与修复

第十一次未出现问题,第九次和第十次作业问题如下:

img

五、JUnit测试实践

1. 基于规格的测试设计

// 验证后置条件
@Test
public void testAddRelation_EnsureSum() {
    int initialSum = network.queryValueSum(tagId);
    network.addRelation(1, 2, 100);
    assertEquals(initialSum + 200, network.queryValueSum(tagId));
}

// 异常场景测试
@Test(expected = RelationNotFoundException.class)
public void testhttps://i-blog.csdnimg.cn/communtity/862a345317964cafabda7109a6496346.png "#left")
ModifyRelation_RemoveNonExist() {
    network.modifyRelation(1, 2, -150); 
}

2. 覆盖率控制

img


六、JML与JUnit协同测试

一、测试逻辑

JML的三种核心结构(ensures、invariant、signals)与JUnit的断言机制形成对应:

  1. 后置条件验证ensures 子句直接转化为 assertEquals
    // JML: ensures \result == size;
    assertEquals(size, collection.size());
    
  2. 不变式检查:类的不变式(如社交值与金额的关系)在每次操作后进行验证,确保对象状态的一致性
  3. 异常处理signals 子句通过 try-catch 结构验证异常的类型和内容

二、测试策略

基于JML的测试具有以下策略优势:

  • 黑盒测试:测试者只需关注规格描述,无需了解具体实现细节,有效分离了设计与验证。
  • 边界条件:JML中\forall\exists引导测试用例覆盖各种边界情况和特殊值。
  • 状态维护:通过检查,确保类的内部状态在任何操作后都保持合法

七、学习收获与疑惑

1. 规格规范开发:记得上OOpre时感叹助教代码写的怎么如此规范,现在能向其一步步靠拢了
2. JML本质上是契约式设计的实践,明确前置条件、后置条件和不变式
3. JML是一个优秀的规格化语言,可以帮助我们避免一些通用语言表达上的二义性问题
4. 在小规模开发上为什么要编写jml?编写jml的功夫不是已经把代码写完了吗?私以为有点过于消耗时间,且jml的正确性又由谁来保证呢?

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

275

社区成员

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

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