『软件测试』学生党期末复习干货 | 万字长文 ⚠

532 阅读50分钟

🔗文末提供获取该提纲的链接(该提纲由任课老师提供,本文仅作整理与细节优化)

💖友情提醒:阅读该文建议搭配目录食用,否则阅读到后半部分容易迷失...

1. 软件测试入门

1.1 软件缺陷

什么是软件缺陷❓

软件缺陷:是指计算机系统或者程序中存在的任何一种破坏正常运行能力的问题、错误,或者隐藏的功能缺陷、瑕疵,其结果会导致软件产品在某种程度上不能满足用户的需要。

从总体上,软件缺陷分为内部错误外部失效

  • 从产品内部看,软件缺陷是软件产品开发或维护过程中所存在的错误、毛病、 瑕疵等各种问题。
  • 从外部看,软件缺陷是系统所需要实现的某种功能的失效或违背,不能满足用 户的需求。

错误 / 缺陷 / 故障 / 失效的联系与区别❓

软件错误:软件生存期内的人为错误,导致人为缺陷产生。是人为过程,相对于软件本身是外部行为。
软件缺陷:存在于软件(文档、数据、程序)中的偏差。导致软件在某个特定条件下出现故障,这时称软件缺陷被激活。
软件故障:软件运行过程中产生的不希望或不可接受的内部状态
软件失效: 软件运行时产生的不希望或不可接受的外部行为结果

⭐联系:

人为的错误(error) -> (代码或文档中静态地存在)缺陷(bug/defect) -> 运行时被激活引发故障(fault) -> 故障严重时导致软件失效(failure)

  • 一个软件错误一定产生一个或多个软件缺陷
  • 但 缺陷不一定要导致故障(除非被触发)
  • 且 故障不一定导致失效(除非很严重并且软件没有应急机制)

1.2 软件质量

什么是软件质量❓

软件质量是软件本身的属性。

软件质量的分类❓

分成以下三类:

  • 内部质量
  • 外部质量
  • 使用质量

😀三者的区别与联系

区别:

  • 内部质量是基于内部视角的软件产品特性的总体,主要是代码的质量
  • 外部质量是基于外部视角的软件产品特性的总体。
  • 使用质量是基于用户观点的软件产品用于指定的环境和使用周境时的质量。它测量用户在特定环境中能达到其目标的程度,而不是测量软件自身的属性。

联系:

  • 内部质量影响外部质量,外部质量影响使用质量,而使用质量依赖外部质量,外部质量依赖内部质量。
  • 外部和内部质量的质量模型(质量属性)
    • 功能性:即软件所实现的功能达到其设计规范和满足用户需求的程度。
    • 可靠性:即在规定的时间和条件下,软件所能维持其正常的功能操作、性能水平的程度/概率。
    • 易用性:即对于一个软件,用户学习、操作、准备输入和理解输出所作努力的程度。
    • 效率:即在指定条件下,软件对操作的响应速度以及实现某种功能有效利用计算机资源的程度。
    • 可维护性:即当一个软件投入应用后,当需求发生变化、环境改变或软件发生错误时,进行相应修改所作努力的程度。
    • 可移植性:即软件从一个计算机系统或环境移植到另一个系统或环境的容易程度,或者是一个系统和外部条件共同工作的容易程度。
  • 使用质量的属性:有效性、生产率、满意度、安全性和语境覆盖。

1.3 软件测试

什么是软件测试❓

是否符合需求(正) vs 存在什么缺陷(反)

正向观点:(正向评估验证)软件测试就是一系列活动,这些活动是为了评估一个程序或软件系统的特性或能力,并确定其是否达到了预期结果。即验证软件系统的每个功能、特性是否符合需求和设计。

反向观点:(反向纠错)

动态测试 / 静态测试的定义与区别❓

  • 动态测试:需要运行软件才能完成测试的一种形式。
  • 静态测试:无需运行软件系统。

⭐区别:主要在于是否需要运行软件系统。

软件测试与 SQA 的联系与区别❓

联系:

  • 软件测试只是软件质量保证工作中的一个环节。
  • 软件测试和软件质量保证是软件质量工程的两个不同层面的工作。

区别:

  • 质量保证(QA):质量保证的重要工作通过预防、检查与改进来保证软件质量。所关注的是软件质量的检查与测量。QA 的工作是软件生命周期的管理以及验证软件是否满足规定的质量和用户的需求,因此主要着眼于软件开发活动中的过程、步骤和产物,而不是对软件进行剖析找出问题或评估
  • 软件测试:测试关心的不是过程的活动,而是对过程的产物以及开发出的软件进行剖析。测试人员要“执行”软件,对过程中的产物——开发文档和源代码进行走查,运行软件,以找出问题,报告质量。对测试中发现的问题的分析、追踪与回归测试也是软件测试中的重要工作,因此软件测试是保证软件质量的一个重要环节。

软件测试的四个层次 (主要活动) 及区别❓

⭐代码层次的单元测试

系统是由单元构成的,所以系统的质量 / 可靠性以依赖于单元的质量 / 可靠性,所以首先要做好单元测试。

⭐接口层次的集成测试

单元接口之间可能存在问题。

⭐系统层次的系统测试

在众多单元成功集成为系统之后,就可以对应用软件的整体系统行为及其表现进行验证,即针对产品的外部质量进行验证

⭐业务层次的验收测试

验收测试就是确认产品是不是真正满足客户 / 用户的实际业务需求。

软件测试的过程模型❓

🉑️参考该博客:测试过程模型(V,W,H,X)

⭐V 模型、W 模型、H 模型。

⭐各个模型的优点和局限性。


V 模型

  • 划分为以下几个不同的阶段步骤:需求分析、概要设计、详细设计、软件编码、单元测试、集成测试、系统测试、验收测试
  • 缺陷:V 模型仅仅把测试过程作为在需求分析、系统设计及编码之后的一个阶段(🤔即开发与测试串行执行),忽视了测试对需求分析,系统设计的验证,需求的满足情况一直到后期的验收测试才被验证
    解决:当一个软件开发的时候,研发人员和测试人员需要同时工作,测试在软件做需求分析的同时就会有测试用例的跟踪,这样,可以尽快找出程序错误和需求偏离,从而更高效的提高程序质量,最大可能的减少成本,同时满足用户的实际软件需求。
W 模型

  • 相对于 V 模型,W 模型增加了软件开发各阶段中同步进行的验证和确认活动
    如图所示,由两个 V 字型模型组成,分别代表测试与开发过程,图中明确表示出了🙄测试与开发的并行关系
  • 测试伴随着整个软件开发周期,而且测试的对象不仅仅是程序,需求、设计等开发输出的文档同样要测试,也就是说,测试与开发是同步进行的。
  • W 模型有利于尽早地全面发现问题。例如,需求分析完成后,测试人员就应该参与到对需求文档的验证和确认活动中,以尽早地找出缺陷所在。同时,对需求的测试也有利于及时了解项目难度和测试风险,及早制定应对措施,这将显著减少总体测试时间,加快项目进度。
  • ⭐优点
    • 测试的活动与软件开发同步进行
    • 测试的对象不仅仅是程序,还包括需求和设计
    • 尽早发现软件缺陷可降低软件开发的成本
  • ⭐局限性
    • 在 W 模型中,需求、设计、编码等活动被视为串行的(开发环节内的活动),同时,测试和开发活动也保持着一种线性的前后关系,上一阶段完全结束,才可正式开始下一个阶段工作。这样就无法支持迭代的开发模型。对于当前软件开发复杂多变的情况,W 模型并不能解除测试管理面临的困惑。
H 模型

  • 相对于 V 模型和 W 模型,H 模型将测试活动完全独立出来,形成了一个完全独立的流程,将测试准备活动和测试执行活动清晰地体现出来。
  • ⭐优点
    • 开发的 H 模型揭示了软件测试除测试执行外,还有很多工作;
    • 软件测试完全独立,贯穿整个生命周期,且与其他流程并发进行;
    • 软件测试活动可以尽早准备、尽早执行,具有很强的灵活性;
    • 软件测试可以根据被测物的不同而分层次、分阶段、分次序的执行,同时也是可以被迭代的。
  • ⭐缺点
    • 管理型要求高:由于模型很灵活,必须要定义清晰的规则和管理制度,否则测试过程将非常难以管理和控制;
    • 技能要求高:H 模型要求能够很好的定义每个迭代的规模,不能太大也不能太小;
    • 测试就绪点分析困难:测试很多时候,你并不知道测试准备到什么时候是合适的,就绪点在哪里,就绪点的标准是什么,这就对后续的测试执行的启动带来很大困难;
    • 对于整个项目组的人员要求非常高:在很好的规范制度下,大家都能高效的工作,否则容易混乱。例如:你分了一个小的迭代,但是因为人员技能不足,使得无法有效完成,那么整个项目就会受到很大的干扰。
X 模型

  • 由图中可见,X 模型还定位了探索性测试,这是不进行事先计划的特殊类型的测试,这一方式往往能帮助有经验的测试人员在测试计划之外发现更多的软件错误。
  • 但这样可能对测试造成人力、物力和财力的浪费,对测试员的熟练程度要求比较高。

软件测试的分类❓

白盒测试 V.S 黑盒测试
  • 白盒测试:通过分析被测单元的内部程序结构来设计测试用例再进行的测试。白盒测试往往是依据程序结构或程序数据流的分析,针对程序语句、路径、变量状态等要素进行测试,检查代码是否按照预期执行的验证工作。白盒测试也称为结构测试或逻辑驱动测试。
  • 黑盒测试:与白盒测试相反,测试不关注内部代码,仅从程序功能和性能上考量是否满足需求而设计测试用例来进行的测试。
自动化测试 V.S 人工测试
  • 自动化测试:相对于手工测试而存在的一种测试形式或测试方式。由手工逐个运行测试用例的操作过程被测试工具或系统自动执行的过程所替代,包括输入数据自动生成、结果的自动验证、自动发送测试报告等。
    • 优点
      1. 提高测试执行效率,节约成本
      2. 解放人力去做更重要的工作
      3. 可重复利用,建设对人的依赖
      4. 提升客户满意度,也可提升测试团队的整体水平
      5. 可大幅度减少兼容性测试的工作量
    • 缺点
      1. 开发测试脚本需要花费较大的时间成本,拉长周期
      2. 产品的快速迭代,自动化脚本也将不断迭代,时间成本很高
      3. 不同项目之间自动化脚本的复用度很低
      4. 自动化无法完全代替手工测试找到 bug,实现 100% 覆盖
      5. 对短期型项目产品实现自动化价值不高
      6. 自动化开发过程对软件测试团队的技术有更高的要求
    • 常用测试工具代码级别:Junit Jmock EclEmma接口/协议级别:JMeter

2. 需求和设计评审

2.1 软件需求

需求的三个层次❓

  • 业务需求
    • 解决什么关键问题,核心的诉求是什么;达到什么目标,这相当于产品的愿景。
  • 用户角色需求
    • 相关利益者的需求,每个用户角色有什么特定的需求。从用户行为去分析,即对应用例 (use case) 或用户故事 (user story),运维、技术支持等相关人员的需求,一般也可以并入用户角色的需求。
  • 功能性和非功能性需求
    • 软件为了满足上述业务需求及相关利益者的需求而具备的功能和非功能性(系统的)能力。

2.2 为什么要进行需求和设计评审

从缺陷的发散效应, 结合 p15 2.1节回答。

缺陷发现得越早、修正得越早、成本就越低。

  • 软件评审是从根本上提高产品的质量,降低软件开发的成本。通过软件评审尽早地发现产品中的缺陷,可以减少大量的后期返工,将质量成本从昂贵的后期返工转化为前期的缺陷发现
  • 需求评审也能带来不少益处。通过产品需求评审,研发人员能更好地理解产品的功能性和非功能性需求,使软件需求被明确描述,其可测试性得到保证,避免在后期产生不同理解而引起的争吵。这就决定了有必要对需求进行评审,设计也是一样。
  • 无论是在统一过程(RUP)还是敏捷时代,设计都是持续迭代的过程,同时,系统的规模越来越大,复杂性增强,技术也在不断创新,系统设计面临更大的挑战,也需要加强设计的评审,通过评审来守护、提高软件的设计质量。

2.3 软件评审的常见形式

作一般性了解即可!

  • 互为评审:相互审查对方的工作成果,帮助对方找出问题。
  • 走查:强调对评审对象从头到尾检查一遍,比互为审查更严格,从而保证其审查的范围全面,达到预定效果。
  • 会议评审:一种系统化、严密的集体评审方法,可以验证产品是否满足功能规格说明、质量特性以及用户需求等,并验证产品是否符合相关标准、规则、计划和过程。

互为评审 & 走查:都不容易发现一些隐藏比较深的问题。

会议(正式)评审的注意事项❓

⭐ p26

3. 单元测试

3.1 什么是单元测试

单元测试是针对软件的基本工作单元进行正确性检验的测试工作。

工作单元是指具有独立功能的单元,一个单元既可以小到只包含一个方法、函数或类,也可以大到包括实现某个功能的多个类和函数。也可以说,单元测试是对软件最小工作单元的测试工作。

3.2 如何开始单元测试

JUnit 的使用❓

⭐测试类和测试方法的定义和使用

  • Junit 测试为白盒测试

Assert(断言)类的常用方法

// 查看对象中存的值是否与期望值相等,与equals()类似
assertEquals()
// 查看变量是否为false或true
assertFalse()
assertTrue()
// 比较两个对象的引用是否相等和不相等 类似 == 和 !=
assertSame()
asserNotSame()
// 查看对象是否为空和不为空
assertNull()
assertNotNull() 
// 意为失败,执行它会直接抛出错误
fail()
// Hamcrest框架中提供assertEquals
assertEquals(except, actual)

JUnit4 常用标注

  • @Test:测试方法,可以测试期望异常和超时时间。
  • @Before:初始化方法,在每一个测试方法执行以前执行。
  • @After:每个测试用例执行之后要执行的方法,一般用于释放参数、释放空间等操作。
  • @BeforeClass:针对所有测试,只执行一次,且必须为 static void(因为是在类实例化之前执行);整个测试类执行之前的操作,常用于准备被测对象或者部署测试环境。
  • @AfterClass:针对所有测试,只执行一次,且必须为static void;整个测试类执行之后的操作,常用来释放对象或恢复测试环境。
  • @Ignore:不执行该测试方法,在测试结果总显示该方法被忽略。

JUnit 框架与运行原理

  • 一个 TestRunner 运行一个 TestSuite,该 TestSuite 可以由一个或多个 TestCase (或者由其他 TestSuite) 所组成。运行结果由 TestResult 收集,由 TestRunner 来报告这些信息。
  • 运行结果:进度条是红色,若是未知的错误 errors,则检查是否测试代码有误;若是 Failures,则断言 Assert 捕获的很可能是程序的 bug。

⭐批量执行测试(参数化)

@RunWith(Parameterized.class) 修饰,表示将在这个类中采用参数化方法执行测试

// JUnit 测试运行器,以参数化方式运行
@RunWith(Parameterized.class)
public class ExampleTest {
    private Example e = new Example();
    private int num;		// 测试用例的输入参数
    private int except;		// 期望值
    
    // 将测试用例集用参数化的方式存入容器中
    @Parameters
    public static Collection<Object[]> testData() {
        return Arrays.asList(new Object[][]{
            {0,0}, {1,1}, {2,1}, {35,324}, {99,2500}, {100,2500}, {101,2601}
        });
    }
    
    // 构造函数初始化
    public ExampleTest(int num, int except) {
        this.num = num;
        this.except = except;
    }
    
    // 测试方法
    @Test(timeout=1000)
    public void testSumOdd() {
        assertEquals(except, e.sumEven(num));
    }
    
}

3.3 单元测试用例设计

逻辑覆盖❓

假设当前有一个 example() 方法需要进行单元测试

public int example(int x, int y, int z) {
    int result = 0;
    if(x>=3 && y==0) {
        result = z + x;
    }
    if(z<=5 || x<z) {
        result = result + x;
    } else {
        result = result + y;
    }
    return result;
}

🚫example() 的程序流程图:

⭐语句覆盖

每个可执行的语句至少被执行一次。

序号覆盖语句测试用例期望
1c,dx=4, y=0, z=6返回 14
2c,ex=8, y=0, z=6返回 14

虽然语句覆盖测试遍历了所有的被测语句,但是其中第一个判定为 "假" 的 b 分支没有语句被忽略而没有被执行。

⭐判定(分支)覆盖

每个判定的 "真" 分支"假" 分支至少执行一次。

序号覆盖路径测试用例期望
1abdx=7, y=8, z=621
2acex=3, y=0, z=28

有可能出现条件出错了(如代码中 x>=3 变成 x<=3), 但是判定覆盖的测试代码并没有改变分支的执行路径(如重新执行序号 2 的测试用例=>测试通过✔❓),从而造成缺陷无法被检测出来。

⭐条件覆盖

每个判定中每个条件的可能值都要至少满足一次。
🔥效果:能发现条件错误,但是不能发现逻辑错误。
🔥注意:条件覆盖和判定覆盖没有胜负之分

对于第一个判定条件(x>=3 && y==0)分解:

① 条件 x>=3:取真值记为 T1T_1,取假值记为 F1F_1

② 条件 y==0:取真值记为 T2T_2,取假值记为 F2F_2

对于第二个判定条件(z<=5 && x<z)分解:

① 条件 z<=5:取真值记为 T3T_3,取假值记为 F3F_3

② 条件 x<z:取真值记为 T4T_4,取假值记为 F4F_4

序号覆盖条件测试用例覆盖分支期望
1T1T_1F2F_2T3T_3F4F_4x=5, y=6, z=4be5
2F1F_1T2T_2F3F_3T4T_4x=2, y=0, z=6be2

满足条件覆盖后,看起来测试覆盖似乎更强了,其实不然。虽然表中两个测试用例覆盖了 8 个条件,满足条件覆盖,但却只是覆盖了程序中的 be 分支,c 和 d 分支都没有覆盖到,并不满足判定覆盖 ❗

🤪从而得出结论:条件覆盖的测试不一定强于判定覆盖,反之亦然。

⭐判定-条件覆盖

每个条件每个分支都至少执行一次。

序号覆盖条件测试用例覆盖分支期望
1T1T_1T2T_2F3F_3F4F_4x=8, y=0, z=4cd14
2F1F_1F2F_2T3T_3T4T_4x=2, y=8, z=6be8

但是,有时某些条件会被其他条件 "短路"(&&||),从而掩盖了新的 Bug 等。

⭐条件组合覆盖

也称多重条件覆盖,每个判定中的所有条件取值组合至少执行一次。

注意⚠:🈵️足多重条件覆盖则满足判定覆盖、条件覆盖、判定—条件覆盖!

表:条件组合列表
条件组合号条件组合条件标记判定取值
1x>=3, y==0T1T_1, T2T_2第 1 个为真
2x>=3, y!=0T1T_1, F2F_2第 1 个为假
3x<3, y==0F1F_1, T2T_2第 1 个为假
4x<3, y!=0F1F_1, F2F_2第 1 个为假
5z<=5, x<zT3T_3, T4T_4第 2 个为真
6z<=5, x>=zT3T_3, F4F_4第 2 个为真
7z>5, x<zF3F_3, T4T_4第 2 个为真
8z>5, x>=zF3F_3, F4F_4第 2 个为假
条件组合覆盖的测试用例
序号组合号测试用例覆盖条件执行路径期望
11,5x=4, y=0, z=5T1T_1, T2T_2, T3T_3, T4T_4ace13
22,6x=4, y=8, z=3T1T_1, F2F_2, T3T_3, F4F_4abe4
33,7x=2, y=0, z=6F1F_1, T2T_2, F3F_3, T4T_4abe2
44,8F1F_1, F2F_2, F3F_3, F4F_4abd

😯注:4 号用例条件矛盾,无测试用例。且条件组合覆盖测试用例缺少 acd 覆盖分支,下文的基本路径覆盖会解决!

缺点:组合数目随着条件数量呈现指数级增长,工作量激增!

🎯覆盖测试的增加是一种手段,不能以追求覆盖率为目的,一味追求逻辑覆盖度,可能反而降低了测试效率。毕竟测试的目标是尽快找到尽可能多的 bug,这种情形下为提高测试效率,则需要考虑测试用例的 "减负",从条件组合覆盖中筛选出最有测试意义的那些测试用例

⭐MC / DC 覆盖

也称修正条件—判定覆盖,它要求生成足够的测试用例满足:

  • 每个程序模块的入口和出口至少要被调用一次。
  • 每个判定的所有分支要执行一次(满足判定覆盖
  • 每个条件的所有可能结果至少需要取一次(满足条件覆盖
  • 每个判定中的每个条件都能独立地影响判定的结果,即在其它所有条件不变的情况下改变该条件的值,使得判定结果改变。

对第一个判定 x>=3 && y==0 进行分析:

① 若 x>=3 为 "真",即 T1T_1,则条件 y==0 会对第一个判定结果独立影响;

② 若 y=0,即 T2T_2,则条件 x>=3 对第一个判定结果独立影响。

则有 T_1$$T_2T_1$$F_2F_1$$T_2 三个用例。

对第一个判定 z<=5 || x<z 进行分析:

① 若 z<=5 为 "假",即 F3F_3,则条件 x<z 会对第二个判定结果独立影响;

② 若 x<z 为 "假",即 F4F_4,则条件 z<=5 对第二个判定结果独立影响。

则有 F3T4F_3T_4F3F4F_3F_4T3F4T_3F_4 三个用例。

整理得到如下 MC / DC 测试用例表:

序号覆盖条件覆盖分支测试用例期望
1T1T_1, T2T_2, F3F_3, T4T_4acex=5, y=0, z=616
2T1T_1, F2F_2, F3F_3, F4F_4abdx=8, y=10, z=610
3F1F_1, T2T_2, T3T_3, F4F_4acex=2, y=0, z=-42

条件组合覆盖要求覆盖判定中所有条件取值的所有可能组合,需要大量的测试用例,实用性不好。

🥰MC/DC 是条件组合覆盖的子集,它具有条件组合覆盖的优势,同时大幅减少了用例数,更有利于真正测试的实施。

到现在为止逻辑覆盖似乎已经走到了最强覆盖,但是观察条件组合覆盖的测试用例表会发现少测试了路径 acd,至此,引出基本路径覆盖 ❗

⭐基本路径覆盖

设计足够多的测试用例,使得执行程序覆盖所有可能的路径

😅路径覆盖并非终极覆盖方法,有时满足路径覆盖但是并不满足条件组合覆盖。😟若是追求高测试覆盖度,可以将二者结合,且还需要采用其他测试方法进行补充,如输入域的无效等价类、数据域的边界值等方法。


修改上文条件组合测试用例,使得测试不仅满足分支覆盖、条件—判定覆盖,而且满足路径覆盖:

序号组合号覆盖条件执行路径
11,5T1T_1, T2T_2, T3T_3, T4T_4ace
21,8T1T_1, T2T_2, F3F_3, F4F_4acd
34,5F1F_1, F2F_2, T3T_3, T4T_4abe
44,8F1F_1, F2F_2, F3F_3, F4F_4abd

路径覆盖是对组合覆盖的加强吗?但是观察上表可得虽然满足了路径覆盖,但是却丢失了 2、3、6、7 的组合,并不满足组合覆盖。

真正要加强覆盖,可以取组合覆盖和路径覆盖测试用例集的并集,如下表:

序号组合号测试用例覆盖条件执行路径期望
11,5x=4, y=0, z=5T1T_1, T2T_2, T3T_3, T4T_4ce13
21,8x=4, y=0, z=7T1T_1, T2T_2, F3F_3, F4F_4cd15
34,5x=2, y=2, z=3F1F_1, F2F_2, T3T_3, T4T_4be2
42,6x=4, y=8, z=3T1T_1, F2F_2, T3T_3, F4F_4be4
53,7x=2, y=0, z=6F1F_1, T2T_2, F3F_3, T4T_4be2
64,8F1F_1, F2F_2, F3F_3, F4F_4bd

😔"逻辑覆盖" 理论上是想要做到测试全面而无遗漏,但一路走来,我们能发现很难做到真正无遗漏。

🧠 因此单元测试用例设计还是需要采用其他测试方法进行补充,如输入域的无效等价类、数据与的边界值等方法(下文介绍)。

控制流图❓ 环形复杂度❓ 基本路径覆盖设计❓

🥰为什么要单独讲解基本路径覆盖设计测试用例的步骤呢?因为期末要考大题且该知识点较为重要!

使用基本路径覆盖法设计测试用例的步骤如下:

① 画出程序的控制流图

⭐控制流图:基本路径覆盖法需要把有复合条件的判定表达式拆解为单个条件表达式来表示。

② 计算程序的环形复杂度

环形复杂度可以导出程序的独立路径数,这时确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界

⭐环形复杂度计算方法 (下列三选一):

  • V (G) = 区域数
  • V (G) = 边数 - 节点数 + 2
  • V (G) = 判定节点数 + 1

补充:判定节点数指的是控制流图中需要判断 True/False 的节点,如图为 1, 2356 这四个判定节点。

图中的 TF 仅为了明显看出控制流图的走向,真正绘画时不需要写出!

③ 确定基本路径

采用 "主路径+转向" 的策略确定基本路径集合:首先寻找一条包含尽可能多分支的路径记录下来作为主路径;然后以主路径为基础,每次只改变一个分支节点的路径选择,以产生新路径。

😵注:基本路径集并不唯一!选择其中一组覆盖到所有基本路径的基本路径集(上述控制流图共 5 条基本路径)如下。

  • 路径 1:(1, 2) => 3 => 4 => 5 => 6 => 8 => END
  • 路径 2:(1, 2) => 3 => 5 => 6 => 8 => END 改变 3 分支
  • 路径 3:(1, 2) => 3 => 5 => 6 => 7 => END 改变 6 分支
  • 路径 4:(1, 2) => 3 => 5 => 8 => END 改变 5 分支
  • 路径 5:(1, 2) => 5 => 8 => END 改变 1, 2 分支
④ 设计测试用例

使得如上基本路径组中的每条路径被执行一次。

路径号条件测试用例期望
1x>=3, y=0, z>5, x<zx=5, y=0, z=6返回 5
2x>=3, y!=0, z>5, x<zx=5, y=3, z=6返回 5
3x>=3, y!=0, z>5, x>=zx=8, y=8, z=6返回 8
4x>=3, y!=0, z<=5x=4, y=3, z=5返回 4
5x<3, z<=5x=2, y=3, z=4返回 2

3.4 避免非测试对象的影响

桩程序、驱动程序、虚拟对象❓

要求:理解相关概念

  • 驱动程序:是用于调用被测模块的替代性程序,用以模拟被测模块的上级模块
  • 桩程序:是对顶层或上层模块进行测试时所编制的替代下层模块的程序,用以模拟被测模块工作过程中所调用的模块。
  • 虚拟 (Mock) 对象:是指在测试过程中,对于不容易构造或者不容易获取的被依赖对象,使用现成的框架动态创建出来的替代品,从而模拟原对象的行为以完成测试。
    • ⭐虚拟对象可以实现桩对象功能,但不能代替驱动程序

Mock V.S. Stub❓

⭐比较异同:

  • Mock:关注行为验证细粒度的测试,即代码的逻辑,多数情况下用于单元测试。Mock 的优点是运行速度快,测试覆盖率高,容易实现且可以形成良好的测试文档。
  • Stub:关注状态验证粗粒度的测试,在某个依赖系统不存在或者还没实现或者难以测试的情况下使用。

掌握一种 Mock 工具的使用❓

EasyMockJMock

🎯 实例化 => 设定期望 => 调用 => 验证

3.5 代码静态分析

常见的代码缺陷模式❓

代码缺陷模式是人们在代码开发时发现的缺陷和遇到的问题的经验总结和问题提炼,不同的开发团队会总结不同的代码缺陷模式,但其中有一些是有共性的模式,具有参考价值。存在如下一些共性模式:

  • 故障模式:此类缺陷会导致软件故障发生,如内存泄漏、空指针错误、数组越界、非法计算、死循环或并发故障等。
  • 安全漏洞模式:这类缺陷会给系统留下安全隐患,为攻击该系统提供了方便。例如,缓冲区溢出模式,数据模式、风险操作模式等。
  • 并发缺陷模式:该模式主要针对程序员对多线程的编码机制、各种同步方法、Java 存储器模式和 Java 虚拟机的工作机制不清楚,而且由于线程启动的任意性和不确定性,使用户无法确定所编写的代码具体何时执行而导致对公共区域的错误使用。
  • 低性能模式:这类缺陷主要包括低效代码、使用多余函数、Java 中显示垃圾回收、头文件中定义静态变量、低效的字符串算法以及其他低效算法和操作等。
  • 程序格式模式:软件开发总是要求遵循一定的规则,违反这些规则是不允许的。如代码规则、控制流规则、命名规则等。
  • 疑问代码模式:如程序总出现令人费解的代码、无意义的代码、执行不到的代码等。

常见的静态分析工具❓

一般性了解

  • PMD
  • FindBugs
  • CheckStyle

3.6 TDD

什么是 TDD❓

  • 在敏捷开发中测试驱动开发 (Test-Driven Development, TDD) 是一项核心实践和技术,也是一种程序设计的新方法,在极限编程 (Extreme Programming, XP) 中会经常用到。测试驱动开发就是在开发功能代码之前先编写单元测试用例代码,通过测试代码来确定需要编写怎样的产品代码。
  • ⭐TDD 是黑盒测试,是最彻底的单元测试!
  • 实现步骤:
    • 编写需求列表,输入与输出(最基本、最常见的输入和输出)
    • 编写一个会失败的单元测试(在实现类还不存在的情况下先编写测试类)
    • 代码开发,让这个测试尽快通过,进度条亮起绿色
    • 重构代码,使代码满足功能需求且能通过测试
    • 继续编写测试进行迭代,增加新的测试用例使得测试失败
    • 修改代码、重构代码并执行测试,使得测试通过
  • 如上是一个简单实现 TDD 的方法构建的过程,😁其精髓就是测试先行持续重构

TDD 的基本循环❓

测试驱动开发 (TDD) 是用比较短的开发测试的循环和循环间的迭代来实现的软件开发过程。其核心的循环如上图:

  • 编写测试,根据功能要求或期望代码改进编写一个会引发失败的单元测试,测试执行进度条是“红”;
  • 开发代码,用最少的代码让测试通过,进度条变为“绿”;
  • 重构代码,使得代码更具实现功能的合理逻辑,并尽可能简单,进度条仍然为“绿”;
  • 返回第一步的编写测试,如此反复迭代,直到所有代码编写完成为止。

4. 持续集成测试

4.1 集成测试及其常见策略

🎯 也称集成测试模式(即按什么方式将被测试过的单元集成到系统中),从传统的测试观点看,集成测试模式分为两类:

  • 非渐增式测试模式。即先分别测试每个模块,再把所有模块按设计要求放在 一起结合成为一个系统,一次性将众多的模块集成起来进行测试,如大棒模式。
  • 渐增式测试模式。即把下一个要测试的模块同已测试好的模块结合起来进行测试,测试是在模块逐个扩展下进行,范围逐步增大。具体来分,可以分为以下几种(🔥了解每种策略的优点、局限性):
    • 自顶向下 (深度优先与广度优先)
    • 自底向上
    • 三明治

🎯大爆炸

大爆炸:又叫大棒集成,是一种非渐增式测试模式,把所有通过了单元测试的模块按设计要求一次全部组装起来,然后进行整体测试

优点:缩短测试时间,使用最少的测试用例验证系统。

缺点:大爆炸集成也称为一次性组装或整体拼装,这种集成测试策略的做法就是把所有通过单元测试的模块一次性集成到一起进行测试,不考虑组件之间的互相依赖性及可能存在的风险。可能发现一大堆错误,为每个错误定位和纠正非常困难。

🎯自顶向下集成

自顶向下集成:按照系统层次结构图,以主程序模块为中心,自上而下按照深度优先或者广度优先策略,对各个模块一边组装一边进行测试。对主模块进行测试,所有直属于主模块的下层模块全部用桩模块代替,再采用深度优先或广度优先的策略,用实际模块替换相应的桩模块,与已测试过的模块或子系统组装成新的子系统。

优点:能尽早地对程序的主要控制和决策机制进行检验,因此较早地发现错误;减少了驱动模块开发的费用。

缺点:在测试较高层模块时,低层处理采用桩模块替代,不能反映真实情况,重要数据不能及时回送到上层模块,因此测试并不充分;需要建立大量的桩模块。

🎯自底向上集成

自底向上集成:从系统层次结构图的最底层模块开始进行组装和集成测试的方式。步骤:由驱动模块控制最底层模块的并行测试,也可以把最底层模块组合起来以实现某一特定软件功能的簇,由驱动模块控制它进行测试。用实际模块代替驱动模块,与它已测试的直属子模块集成为子系统。为子系统配备驱动模块,进行新的测试。判断是否已集成到达主模块,是否结束测试,否则继续向上迭代集成。为避免引入新错误,还需要不断地进行回归测试,即全部或部分地重复已做过的测试。

优点:自底向上集成方法不用桩模块;多个模块可并行测试,提高测试效率;测试用例的设计亦相对简单(因驱动模块+模块群构成的子系统只是完成特定功能,而不是全部功能)。

缺点:程序到最后一个模块加入时才具有整体形象,即对程序的主要控制直到最后才接触到;需要大量驱动模块。

🎯三明治集成

三明治集成:三明治集成是一种混合增殖式测试策略,综合了自顶向下和自底向上两种集成方法的优点

🧡方法:一般对软件结构的上层使用自顶向下结合的方法,对下层使用自底向上结合的方法。

步骤:

  • 首先,确定以哪一层为界来决定使用三明治集成策略。我们假设以 B 模块为界;
  • 其次,对模块 B 及其所在层下面的各层使用自底向上的集成策略;
  • 再来,对模块 B 所在层上面的层次使用自顶向下的集成策略;
  • 然后,把模块 B 所在层各模块同相应的下层集成;
  • 最后,对系统进行整体测试。

优点:除了具有自顶向下和自底向上两种集成策略的优点之外,运用一定的技巧,能够减少了桩模块和驱动模块的开发。

缺点在被集成之前,中间层不能尽早得到充分的测试

4.2 持续集成 CI 的概念

集成测试伴随着单元测试,每日构建一次或多次集成,还不能算持续集成,持续集成还需要做到:

① 构建是自动完成的。

② 所构建的版本是被自动验证的,尽可能快地发现集成的问题。

⭐简单地说,持续集成包括:自动构建自动部署自动验证

🙄持续集成不是目的,而是手段。通过实现持续集成,不仅能及时发现集成问题,它还是持续交付 (Continuous Delivery, CD) 的前提,持续交付才是最终目的

4.3 持续集成的好处

1)快速发现错误:每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。

2)防止分支大幅偏离主干:如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。

4.4 CI 环境

了解常见的构成 CI 环境的工具名称

源码管理工具❓

CVSSubversion(SVN)、GitFossilMercurial(Hg)、GNU BazzarPerforceBorlandAccuRev

构建工具❓

  • 依赖 Java 语言的代码工具:Ant \ Maven \ Gradle(Groovy) \ Buildr
  • 依赖 C/C++ 语言的代码工具:makeBuildAMation
  • 依赖 Ruby 语言的代码工具:Rake Capistrano
  • 依赖 .NET 语言的代码工具:NAnt \ MSBuild

CI 管理工具❓

Jenkins 安装和使用见实验报告!

4.5 持续集成的一般过程

以 Jenkins 为例,如下图,理解其整个工作流程

主要流程:来自开发的源代码的更新 —> 源代码控制仓库 —> 检出 —> 项目工作空间 —> 构建 —> 部署 —> 测试 —> 发布 —> 可交付件仓库。

其中:构建、部署、测试、发布都需发布报告和通知

5. 系统功能测试

5.1 测什么

不同的应用系统其测试内容的差异很大,但都可以归结为功能、逻辑、接口、界面、数据、操作、平台等几个方面。

5.2 基本思路

系统测试的基本思路可以简单地概括如下:

① 明确测试目标和质量要求,包括阅读需求和设计等相关文档、与项目干系人(开发人员、产品经理等)沟通交流。
② 对测试需求进行分析,获得测试项,包括确定积累一定的经验之后,还可进一步分析测试的难点和重点,设定测试项的优先级。
③ 根据所确定的测试项,选择合适的测试方法和技术、工具。
④ 根据所选的测试方法,进行测试设计或脚本开发。
⑤ 准备好测试环境并执行测试,观察测试结果;如果有缺陷,就把问题报告出来。
⑥ 评估测试结果和过程,如果没有达到测试目标,再进行进一步测试需求分析或选择更好的测试方法,或补充测试用例,形成一个循环改进的过程,直至达到测试目标。
⑦ 一旦达到测试目标,系统地阐述测试过程和结果,提交测试报告。

5.3 功能测试用例设计

🎯掌握黑盒测试用例设计的方法

🎯重点掌握等价类划分边界值分析决策表法

基于输入域的方法❓

⭐等价类划分

理解:什么是等价类、有效等价类、无效等价类

  • 等价类:指某个输入域的一个特定的子集合,在该子集合中各个输入数据对于揭露程序中的错误都是等效的(也就是说,如果用这个等价类中的代表值作为测试用例未发现程序错误,那么该类中其他的数据(测试用例)也不会发现程序的错误)
  • 有效等价类:指我完全满足程序输入规格说明、有意义的输入数据所构成的集合(利用有效等价类可以检验程序是否满足规格说明所规定的功能和性能)
  • 无效等价类:由不满足程序输入要求或无效的输入数据构成的集合
⭐边界值分析
举例

成绩转换程序:分数在 100-90、89-80、79-70、69-60、59-0 分别转换为对应的 A、B、C、D、F 等级

  • 🤔使用 等价类划分 得到的测试用例:-10、20、66、77、85、95、130、100、90、89、80、79、70、69、60、59、0(后 10 位是边界点)
  • 🙄使用 边界值分析 得到的测试用例:0、59、60、69、70、79、80、89、90、100 作为边界,每个边界点测 3 个数据

组合测试❓

⭐决策表 (判定表)

🎯P176 ~ P178

  • 借助表格方式完成对输入条件的组合设计,以达到完全组合覆盖的测试效果
  • 一个判定表由条件(即条件桩)和动作(即动作桩)两部分组成,条件作为输入、动作作为输出
⭐Pairwise 方法

🎯P179 ~ P180

😀Pairwise 算法过程:从表的最后一行开始,如果这行的两两组合值能够在上面的行或此表中找到,那么这行就可从用例集中删除。

理解了 pair-wise 算法后,就会觉得 pair-wise 方法相当简单!

举例:A : A1、A2;B : B1、B2;C : C1、C2、C3 全部组合,需要 2 x 2 x 3 两两组合(判定表法),使用 Pair-wise 方法只要以下 6 个组合即可:

  • A1 B1 C1
  • A1 B2 C2
  • A2 B2 C1
  • A2 B1 C2
  • A2 B1 C3
  • A1 B2 C3

缺点:覆盖率比较低

正交实验法(了解)

🎯P180

  • 使得测试数据更为均匀、有效
  • 正方体原始由 27 个点 3 x 3 x 3 正交试验设计后 (剩 9 个):
    • A1B1C1A_1B_1C_1A1B2C2A_1B_2C_2A1B3C3A_1B_3C_3
    • A2B1C2A_2B_1C_2A2B3C1A_2B_3C_1A2B2C3A_2B_2C_3
    • A3B1C3A_3B_1C_3A3B2C1A_3B_2C_1A3B3C2A_3B_3C_2
  • 任何一个面都有 3 个点,且任何一条线只有 1 个点,任何一个方向俯视图正好覆盖 9 个点
  • 对三个因素、每个因素取三个值、两两组合方法的结果和正交实验法的结果是一致的

基于场景的方法❓

  • 场景法:模拟用户操作软件时的情景,主要用于测试系统的业务流程
  • 场景又分:
    • 基本流
    • 正确路径备选流
    • 错误路径

5.4 什么是回归测试

⭐在软件研发过程中,软件未被修改的部分因为其他地方的代码修改而产生缺陷,这种缺陷是回归缺陷回归测试就是为了发现这类问题而进行的测试

回归测试用例集❓

一个版本的测试用例集分解为三部分:

① 上一个版本保留下来的用例子集,不需要修改,包含依旧有效的测试用例。

② 由于功能变动(变更)、缺陷修复而需要修改的用例子集,也是有效的测试用例,只是从上个版本集成下来之后进行了修改。

③ 由于功能变动(变更)而删除的无效用例子集,也许不删除,但会置为 “invalid” 或 “inactive” 状态的。

而为当前版本新功能增加的测试用例,可以看做额外的第 4 部分测试用例集。

严格来说,回归测试用例集是第 1 子集;如果不够严格,回归测试用例集包括第 1、 2 两个子集。

在实际项目中,回归测试用例集(子集1,或子集1 + 子集2)中的测试用例数量很多,往往远远超过子集4。

回归测试策略❓

⭐基于风险策略来选择回归测试用例

优先变动大的代码进行测试,即判断哪些区域受修改的代码影响的可能性大,受到影响的可能性越大,越要优先考虑。如果测试用例没有收到影响,这些用例就不选择。

⭐基于操作剖面选择测试

优先测试较为重要的,使用频繁的功能。如果测试用例的构造是基于用户功能特性组织的,测试用例的分布情况反映了系统的实际使用情况,则选择这种策略。优先选择那些最重要的,或者最频繁使用的功能所关联的测试用例,有助于尽早发现那些对质量有明显影响的故障,而放弃次要功能关联的测试用例。

⭐采用代码相依性(相互依赖的关系)分析

优先测试和变动代码有关联的代码。

5.5 系统功能测试工具 QTP 的基本使用

检查点、参数化、输出值与 Action 的拆分❓

了解相关概念和操作,见实验报告。

5.6 面向接口的测试

什么是接口测试❓

接口测试主要用于检测外部系统与系统之间、以及系统内部各个子系统、组件之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等

为什么要进行接口测试❓

  • 由于如今的系统复杂度不断上升,传统的测试方法成本急剧增加且测试效率大幅下降。而接口相对 UI 而言更为稳定(不易变),进行接口测试可以减少人工回归测试的成本与时间缩短测试周期,支持后端快速发版需求。
  • 并且接口测试相对容易实现自动化持续集成
  • 从安全层面来说,现在很多系统前后端架构是分离的,只依赖前端进行限制已经完全不能满足系统的安全要求(绕过前端实在太容易), 需要后端同样进行控制,在这种情况下就需要从接口层面进行验证。前后端传输、日志打印等信息是否加密传输也是需要验证的,特别是涉及到用户的隐私信息,如身份证,银行卡等。

常见的 Web 接口测试分类及工具❓

分类:

  • ① 基于 SOAP 接口
  • ② 基于 REST 接口

工具:以 Postman 为例,了解基本方法即可

5.7 Web 应用测试

Selenium + WebDriver 实现 Web 自动化测试❓

掌握使用 Selenium 进行 Web 自动化测试的一般流程

  • Selenium + WebDriver 的基本原理
  • 浏览器的打开与退出
  • 页面元素的定位
  • 页面元素的操作

5.8 什么是探索式测试

没有详细、书面的测试用例也可以执行测试,即靠在头脑中设计,一面设计、一面执行、一面学习,不断地优化测试,持续地开展测试。这就是探索式测试 (exploratory testing),强调测试的学习、设计和执行同时进行

6. 系统性能测试

6.1 什么是系统性能测试

性能测试(performance test)就是为了发现系统性能问题或获取系统性能相关指标而进行的测试。一般在真实环境、特定负载条件下,通过工具模拟实际软件系统的运行及其操作,同时监控性能各项指标,最后对测试结果进行分析以确定系统的性能状况。

系统性能测试不是精准的测试,其目标通常是为了获取系统性能某些指标数据,或为了验证系统是否达到用户提出的性能指标, 以及发现系统中存在的性能瓶颈,优化系统的性能

6.2 不同类型的性能测试

主要是目的不同,简单了解即可。

负载测试❓

通过模拟实际软件系统所承受的负载条件(如在线连接数、并发用户数等)、改变系统负载大小和负载方式来发现系统中存在的问题。

狭义的性能测试❓

是为获取或验证系统性能指标而进行的测试。

容量测试❓

一般是通过不断增加负载直至系统崩溃,从中确定系统能够正常运行的负载。

压力测试❓

可以被看作是高负载(如大数据量、并发用户数高等)或极限负载(系统使用峰值)下的测试。

6.3 性能测试的关键指标

掌握几个关键性能指标及其含义

  • 系统 / 事务平均响应时间
  • TPS (系统吞吐量)
    • 每秒钟用户系统能够处理的交易或者事物的数量,它是衡量系统处理能力的重要指标
  • PV (网页浏览量)
    • 用户向 server 发送请求,server 处理一次真实的请求
  • 吞吐率
    • 即每秒服务器处理 HTTP 申请数
  • 每秒点击次数
  • 内存和 CPU 使用率

6.4 负载及其相关概念

并发用户 V.S. 在线用户❓

⭐在线用户数:用户同时在一定时间段的在线数量

⭐并发用户数:某一时刻同时向服务器发送请求的用户数

虚拟用户(VU)❓

虚拟用户的模拟

  • 进程方式模拟虚拟用户
    • 一个进程模拟一个用户,多少个用户就又多少个进程,而每个进程会占用一定的资源,所以一个负载生成器只能生成较少的虚拟用户。
    • 优点:模拟过程相对稳定
    • 缺点:占用较多的资源
  • 线程方式模拟虚拟用户
    • 每个虚拟用户由一个线程来完成模拟,每 30~50 个线程(用户)共享一个进程(一个内存段)
    • 优点:节省了大量内存空间
    • 缺点:不够稳定

思考时间❓

用户在不同操作之间会有所停顿,其间隔时间可以理解为思考的快慢,所以它被定义为思考时间。

负载模式❓

三部曲

负载模式的三部曲包括启动持续进行结束

  • 启动:虚拟用户如何进入测试现场,是同时加载所有虚拟的并发用户还是分阶段逐渐加载用户。
  • 持续时间:到达最大负载后,继续运行多长时间。
  • 结束:和启动相对应,如在某个时刻全部停止所有虚拟用户的操作,或分阶段逐渐减少用户,直至所有虚拟用户退出。

在工具 JMeter 中通过为每个负载测试设置线程数、启动周期和循环次数等参数值实现

四种加载模式
  • 一次加载:一次性加载某个数量的用户,在预定的时间段内持续运行。获取某种确定负载下的性能指标数据,一般也采用这种加载模式。
  • 递增(递减)加载:用户有规律的逐渐增加,每秒或每几秒增加一些新用户,交错上升,这种方式又被称为 ramp-up 模式。在容量测试、破坏性压力测试(发现性 能拐点、确定负载极限)中,一般选用这种加载模式。
  • 髙低突变加载:某个时间用户数量很大,之后突然降到很低,过一段时间又突然加到很高,往复多次。借助这种负载方式的测试,容易发现资源释放、内存泄漏等问题,这也是前面所说的压力测试中的 "峰谷测试"。
  • 随机加载方式:由随机算法自动生成某个数量范围内变化的、动态的负载, 这种方式可能是和实际情况最为接近的一种负载方式。虽然不容易模拟系统运行出现的瞬时高峰期,但可以模拟处在比较长时间的高位运行过程

同步点❓

⭐同步点,也称集合点,就是当足够的虚拟用户到达同步点时才执行所设定的动作

6.5 性能测试工具的关键特性

作为性能测试工具:

  • 模拟用户行为产生负载
  • 产生大量的虚拟用户
  • 驱动、监控和管理整个性能测试过程
  • 生成性能测试报告
  • 通过录制产生性能测试脚本
  • 性能测试脚本参数化

JMeter 的八大组件及其基本使用❓

掌握 JMeter 中常见组件的分工和基本使用

⭐重点掌握:

  • 采样器:产生符合某种通信协议的数据包,模拟负载能力体现在性能测试工具能支持多少种不同的协议
  • 逻辑控制器:定义发送请求的行为逻辑
  • 后置处理器:用来出处理响应的数据
  • 断言:用来判断请求响应的结果是否如所期望的结果,帮助功能测试进行验证

具体操作见实验报告

6.6 性能测试的一般过程

⭐过程:测试计划 => VUser 脚本开发 => 定义场景 => 执行场景 => 分析结果

性能测试脚本开发一般有两种方式实现:

1、先录制脚本,然后在录制脚本的基础上修改、重构或扩充。
2、直接根据工具提供的脚本语言、接口进行脚本开发。

分析结果时注意关注拐点

7. 测试与缺陷管理

7.1 测试风险控制

一般性了解

常见风险识别❓

控制风险的策略❓

常见的有:

  • 消除执行风险:通过系统复审、测试人员之间互审、测试人员在不同测试模块上相互调换、自动化 测试和抽查等方法。
  • 降低进度风险:进行测试资源、时间等估算时要留有余地,增加10%的缓冲空间,以减低测试资源可能不足的风险。
  • 减少人员风险:对每个关键性技术人员培养后备人员,做好不同领域知识的培训,从而确保有关人员一旦离开公司,项目不会受到严重影响

7.2 缺陷管理

软件缺陷生命周期❓

必考!

缺陷的属性❓

属性:

  • 缺陷 ID
  • 标题
  • 测试环境
  • 前置条件
  • 测试输入
  • 操作步骤
  • 实际结果和所期望的结果

可能性(频率):总是、通常、有时、很少

严重性:0级(致命)、1级(严重)、2级(一般)、3级(较小)

优先级:立即解决(p1级)、高优先级(p2级)、正常排队(p3级)、低优先级(p4级)


⭐严重性、优先级的联系和区别

严重性:衡量缺陷对客户满意度的影响程度

优先级:指缺陷被修复的紧急程度

😵注意:一般来说,缺陷越严重,越要优先得到修正,缺陷严重等级和缺陷优先级相关性很强。但是,有时也不尽然。例如,如下几种情况:

  • ① 从客户角度看缺陷不是很严重,但可能影响下面测试的执行,这时缺陷严重性低,但优先级高,需要尽快修正。
  • ② 有些缺陷比较严重,但由于技术的限制或第三方产品的限制暂时没法修正,其优先级就会比较低。

有效描述缺陷❓

如何有效地报告软件缺陷:

  • 单一准确:每次报告只针对一个软件缺陷。
  • 可以再现:缺陷操作步骤的准确描述是开发人员可以再现缺陷的重要保证。
  • 完整统一:提供完整的软件缺陷描述信息。
  • 短小简练:通过使用关键词,可以使软件缺陷的标题描述短小简练,又能准确解释产生缺陷的现象。
  • 特定条件:在软件缺陷描述中不要忽视看似细节但是必要的特定条件(如特定的操作系统、浏览器或某种设置等)。
  • 不做评价:在软件缺陷描述不要带有个人观点,对开发人员进行评价。

使用缺陷管理工具来跟踪和处理缺陷❓

Bugfree 为例,了解缺陷从打开到关闭整个生命周期中的相关角色及其操作。

7.3 软件测试原则

1. 及早和不断地测试

从项目启动的第一天,测试人员就参与项目的各种活动和开展对应的测试活动。在代码完成之前,可以进行各种静态测试,主导或积极参与需求文档、设计文档的评审,做好充分的前期工作和测试环境的部署。

2. 80/20 原则

用户 80% 的时间在使用软件产品中 20% 的功能。

3. 测试阶段性

一方面,应根据软件开发生命周期的不同阶段性任务来决定相应的测试目标和任务,如在需求分析和设计阶段要参与需求评审和设计评审。

4. 测试独立性

除非采用 TDD 实践,最好让开发人员彼此独立于各自的代码,相互测试,或者采用由相对独立的测试角色、测试小组来测试开发人员编写的代码。

5. 测试客观性

事先定义好产品的质量特性指标,测试时才能有据可依。有了具体的指标要求,才能依据测试结果对产品的质量进行客观的分析和评估,即能确定客观的测试预言。

6. 计划是一个过程

测试计划应在测试各项活动中遵循测试计划。

7. 测试是开发的一部分

测试的反复性。开发人员和测试人员的工作不能分离,实现和验证是交互进行的。

8. 发现缺陷更多的地方,其风险更大

缺陷的群集效。一般来说,软件的一个程序模块中已发现的错误数越多,意味着这个模块的质量越不好。


⭐边复习边整理,耗时 2 天,希望本文对你有所帮助。

链接:pan.baidu.com/s/1DWlG9iSG…
提取码:887g