BUAA-OO-U3 博客

王怀阳-22373568 学生 2024-05-19 15:26:11

目录

  • 1. 测试过程
  • 1.1 黑箱测试 & 白箱测试
  • 1.2 各种测试
  • 1.3 数据构造策略
  • 2. 架构设计
  • 2.1 图模型策略
  • 2.2 维护策略
  • 3. 性能 & 规格与实现分离
  • 3.1 性能问题
  • 3.2 规格与实现分离
  • 4. Junit测试
  • 5. 学习体会

1. 测试过程

1.1 黑箱测试 & 白箱测试

  • 黑箱测试(Black Box Testing): 黑箱测试也被称为功能测试,是一种不考虑内部结构和实现的测试方法。在黑箱测试中,软件被视为一个黑箱,测试人员只关注输入和输出,而不关注软件的内部结构。黑箱测试的主要目标是验证软件的功能性和可用性。
  • 黑箱测试的主要步骤包括:
    1. 确定测试的需求和条件。
    2. 根据需求设计测试用例。
    3. 执行测试用例并记录结果。
    4. 对比实际结果和预期结果,如果两者一致,则测试通过;否则,需要进行调试和修复。
  • 白箱测试(White box testing): 白箱测试也被称为结构测试或逻辑驱动测试,是一种需要了解软件内部结构和工作原理的测试方法。在白箱测试中,测试人员需要了解软件的内部逻辑,以便设计覆盖所有可能路径的测试用例。
  • 白箱测试的主要步骤包括:
    1. 了解软件的内部结构和逻辑。
    2. 设计测试用例以覆盖所有可能的执行路径。
    3. 执行测试用例并记录结果。
    4. 对比实际结果和预期结果,如果两者一致,则测试通过;否则,需要进行调试和修复。

1.2 各种测试

  1. 单元测试(Unit Testing):一种对软件中的最小可测试单元进行检查的过程。通常,一个单元是一个特定功能的一部分,如一个函数或方法。单元测试主要用于验证每个单元的功能是否正确。

  2. 功能测试(Functional Testing):一种黑箱测试过程,用于验证系统的功能是否符合预定的需求。这种测试主要关注的是软件系统的外部行为,而不是内部结构。

  3. 集成测试(Integration Testing):在单元测试的基础上,集成测试是将这些单元组合在一起并测试的过程。这有助于发现单元之间交互时可能出现的问题。实践表明,一些模块虽然能够单独地工作,但并不能保证连接起来也能正常的工作。一些局部反映不出来的问题,在全局上很可能暴露出来。

  4. 压力测试(Stress Testing):一种测试方法,用于确定系统在高负载或压力条件下的行为。这可以包括测试系统在大量用户同时访问时的行为,或者在资源(如CPU、内存或磁盘空间)有限时的行为。

  5. 回归测试(Regression Testing):在迭代开发的场景下,每次修改了软件的一部分或进行了一些更新后,都需要进行回归测试。这是为了确保修改没有引入新的错误,或者没有重新引入旧的错误。

1.3 数据构造策略

  • 主要是通过随机生成的方法,以及针对单独指令进行压力测试。

2. 架构设计

  • 由于接口中的JML已经给出了非常详细的规格指导,大框架只需要照着内容去搭建即可。

2.1 图模型策略

  • 本单元主要要求我们以Person为点,Person间的relation为边,再加上一些奇怪的属性(比如Tag、Message)来构建一张图。由于担心自己在写并查集删边的时候写错或者爆掉导致一些奇怪的bug,我并没有使用并查集的数据结构,只是用了一些朴素的搜索以及一些简单的优化,达到尽量不要出现$O(n^2)$的方法。事实证明,这样也能达到评测的需求。

2.2 维护策略

  • 维护了一些简单的属性,如Network的tripleSum、Person的BestfriendID、Tag的一些平均数、平方和等等。

3. 性能 & 规格与实现分离

3.1 性能问题

  • 在第十次作业中,由于偷懒把获取Tag的ValueSum的方法写成了$O(n^2)$,后来将其改成$O(m)$就过了(虽然这样感觉更多是针对数据点来debug,出现边数多的图时也可能会爆,汗。采用动态维护的话才能根本性解决这一问题)
// 原先n^2的写法
public int getValueSum() {
    int valueSum = 0;
    for (Person person : persons.values()) {
        for (Person other : persons.values()) {
            if (person.isLinked(other)) {
                valueSum += person.queryValue(other);
            }
        }
    }
    return valueSum;
}

// 改成边数的复杂度
public int getValueSum() {
    int valueSum = 0;
    for (Person person : persons.values()) {
        for (Person other : ((MyPerson) person).getFriends().values()) {
            if (persons.containsKey(other.getId())) {
                valueSum += person.queryValue(other);
            }
        }
    }
    return valueSum;
}

3.2 规格与实现分离

  • 在本单元中,规格为我们定义了一种基础实现方法,我们的任务是优化这种方法,确保优化不引入副作用。例如将 EmojiList 和 EmojiHeatList 合并成一个 HashMap 等。
  • 我们作为实现者,可以将 JML 看成一个更详尽的需求指导书,而在高性能要求的实现场景下,还需另起炉灶,采用合适的数据结构与算法来进行代码编写。

4. Junit测试

主要有以下几点需要注意:

  • 深拷贝需要检测的对象
  • 数据生成时采用随机的构造方法,但同时需单独构造极值的测试数据,专门用来测试边界条件
  • JML 中出现的属性如 pure、invariant、not_assigned 以及每条 ensure 都需考虑到
  • 迭代场景下注意使用回归测试

5. 学习体会

  • 经过这一单元的学习,我了解了 JML 规格和其语法,也在强侧出 bug 后对规格与实现分离有了更深刻的认识。
  • 在实际的软件开发中,我们其实不需要对每个方法都大费周章,设计如此详细繁杂的规格,但在高精度开发场景下,比如航空航天领域,我们需要严格满足规格的要求,以保证系统的质量。
...全文
60 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

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

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