软件构造学习心得之测试&测试优先程序

目录

1 软件测试(Sowftware Testing)

1.1 测试等级

1.2 静态测试&动态测试(Static testing&Dynamic testing)

1.3 白盒测试&黑盒测试(White-box testing&Black-box testing)

2 编写测试优先程序(Test-First Programming)

3 使用Junit进行单元测试

4 等价类划分(Equivalence Partitioning)

5 代码覆盖度(Coverage of Testing)

6 知识框图


1 软件测试(Sowftware Testing)

软件测试是提高软件质量的重要手段,通过软件测试,可以尽早,尽快的发现Bug。软件测试跟其他软件构造活动的目标相反:软件测试总是试图通过一些特殊用例,或者一些非法输入,来破坏软件的正常运行。软件测试的目的是在于检测和发现Bug,因此软件测试通过,并不能证明程序是正确的,他只能表示在这种情况下,软件是可运行的。所以说,再好的测试也无法证明系统里不存在错误。一个好的软件测试,应该能够检测到程序的Bug,而且最佳特性,多种测试方案中最好的。

1.1 测试等级

常用测试等级可分为三类:系统测试System testing,集成测试Integration testing,单元测试Unit testing。

图1 测试等级

 其中,单元测试主要是对方法和类的测试,集成测试则是对类和包的测试,而系统测试是对整个系统的测试。受限于实验,我们所接触的大多都是单元测试。而单元测试用两种主要的模块,一个是Driver驱动模块,一个是Strubs桩模块。个人理解:在主函数main中进行的测试就是Driver驱动模块,而采取Junit的测试框架就是Strubs桩模块。

1.2 静态测试&动态测试(Static testing&Dynamic testing)

静态测试:不实际执行程序,通常隐式,比如校对,编程工具/文本编辑器检查源代码结构,编译器(预编译器)检查语法和数据流等等。

动态测试:动态测试描述了代码的动态行为的测试,它实际地使用给定的测试用例集执行已编程的代码。

1.3 白盒测试&黑盒测试(White-box testing&Black-box testing)

白盒测试:对程序内部代码结构的测试

黑盒测试:对程序外部表现出来的行为的测试,用于检查代码功能,不关心内部实现细节,测试用例通常来自软件的外部描述,包括规格说明、需求和设计参数

白盒测试是站着开发者的角度进行编写的测试,涉及到实现内部,而黑盒测试则是站在client的角度,并不关心内部实现,只在乎对于符合要求的输入,其输出结果是否正确。

2 编写测试优先程序(Test-First Programming)

为什么要编写测试优先程序?

编写测试优先程序测有助于更好地理解规约。实际上,开发者不得不面对的一个重要问题是,规约本身也可能是错误的,不正确,不完整,模棱两可,缺失边界情况。通过编写测试用例,可以及时尽早的修改,补充规约。在实际开发中有着重要的意义,避免了client和实现者之间的误解与冲突,减少代码变动。 其次,测试优先可以尽 早发现设计问题,避免浪费时间做错误的事情。实际数据统计也表明,先编写测试用例会大大减少调试时间。总之,测试优先程序的优点总结如下:

  1. 更深入和更早的理解需求和设计
  2. 更早地暴露需求和设计的问题
  3. 可确保程序的可测试性
  4. 确保每个程序特征的测试 都撰写完成
  5. 确保程序功能的正确实现
  6. 更早更快的修改错误

编写测试用例优先程序的流程总体如下:

  1. 根据client的需求编写spec(规约)
  2. 依据spec编写测试用例(Test case)
  3. 完成代码,运行测试用例,依据测试结果,修改并完善代码

一些注释:spec全称Specification(规约),是实现者和client进行交流沟通的注释文档,用来阐述函数功能,参数需要以及返回值。更加具体的规约介绍会在设计规约中详细介绍。

3 使用Junit进行单元测试

使用Junit单元测试时, 在每个测试方法前面使用@Test标注指明 

常用的测试语句:

测试语句
assertEquals(a,b)a与b相等
assertTrue(b)b的值为True
assertFalse(b)b的值为False

参数顺序:第一个参数是预期结果,第二个参数是实际结果

注意:各个test相互独立运行

示例:

    public void testAdd() {
    	Graph<String> graph=emptyInstance();
    	String V1="A";
    	String V2="B";
    	String V3="C";
    	String V4="D";
    	assertEquals(true,graph.add(V1));
    	assertEquals(true,graph.add(V2));
    	assertEquals(true,graph.add(V3));
    	assertEquals(true,graph.add(V4));
    	assertEquals(false,graph.add(V1));
    	assertEquals("{[A, B, C, D],[]}",graph.toString());
    }

4 等价类划分(Equivalence Partitioning)

等价类划分主要应用于黑盒测试,单元测试。其基本思想是,将测试用例划分成几个等价类,然后在每一个等价类中选取少量用例便可以代表整个等价类来进行测试,多与边界值分析Boundary Value Analysis(BVA)组合使用(边界值分析:选取最容易出错的边界进行测试)。对于等价类的划分需要根据具体情况进行具体分析,将输入和结果组成键值对,如果一组对象间存在对称、传递和自反的关系,则认为是等价类。

一般操作如下:

  • 单故障假设
  • 一般根据输入来进行等价类划分

示例:测试一个在有向带权图中加入边的方法,可以看到根据输入的起始点,目标点以及边权进行的等价类划分:

    /*
     * Testing strategy
     * 有效等价类:
     * 加入边的等价类划分:不存在,已存在
     * 按权重划分:权重为正数,权重为0
     * 按顶点划分:顶点存在,一个顶点不存在,两个顶点不存在
     * 无效等价类:
     * 权值为负
     */
    @Test
    public void testSet() {
    	Graph<String> graph=emptyInstance();
    	String V1="A";
    	String V2="B";
    	String V3="C";
    	String V4="D";
    	String V5="E";
    	String V6="F";
    	String V7="G";
    	String V8="H";
    	graph.add(V1);
    	graph.add(V2);
    	//不存在,权为正,顶点存在
    	assertEquals(0,graph.set(V1, V2, 5));
    	assertEquals("{[A, B],[(A,B,5)]}",graph.toString());
    	//不存在,权为正,一个顶点不存在
    	assertEquals(0,graph.set(V1, V4, 3));
    	assertEquals("{[A, B, D],[(A,B,5), (A,D,3)]}",graph.toString());
    	//不存在,权为正,两个顶点不存在
    	assertEquals(0,graph.set(V3, V5, 2));
    	assertEquals("{[A, B, C, D, E],[(A,B,5), (A,D,3), (C,E,2)]}",graph.toString());
    	//不存在,权为0,顶点存在
    	assertEquals(0,graph.set(V1, V3, 0));
    	assertEquals("{[A, B, C, D, E],[(A,B,5), (A,D,3), (C,E,2)]}",graph.toString());
    	//不存在,权为0,一个顶点不存在
    	assertEquals(0,graph.set(V1, V6, 0));
    	assertEquals("{[A, B, C, D, E],[(A,B,5), (A,D,3), (C,E,2)]}",graph.toString());
    	//不存在,权为0,两个顶点不存在
    	assertEquals(0,graph.set(V7, V8, 0));  
    	assertEquals("{[A, B, C, D, E],[(A,B,5), (A,D,3), (C,E,2)]}",graph.toString());
    	//存在,权为正,顶点存在
    	assertEquals(5,graph.set(V1, V2, 9));  
    	assertEquals("{[A, B, C, D, E],[(A,B,9), (A,D,3), (C,E,2)]}",graph.toString());
    	//存在,权为0,顶点存在
    	assertEquals(3,graph.set(V1, V4, 0));   
    	assertEquals("{[A, B, C, D, E],[(A,B,9), (C,E,2)]}",graph.toString());
    }
    /*

5 代码覆盖度(Coverage of Testing)

代码覆盖度是用来评价测试用例是否完备的方法:

  • 函数覆盖度Function coverage:每个函数是否被调用
  • 语句覆盖Satement coverage:每个语句是否被执行
  • 分支覆盖Branch coverage:对于程序中的每一个if或while或switch-case或for语句,测试用例是否同时采用了true和false方向,即,每个分支都要有真假两个方向
  • 条件覆盖Condition coverage:每个条件判断式都采过等价类划分的取值
  • 路径覆盖Path coverage:是否每个可能的分支组合——通过程序的每一条路径——都被一些测试用例所采用

6 知识框图

图2 知识框图

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值