问题一 断言assert()函数的使用
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行。原型定义:
#include <assert.h>
void assert( int expression );
assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。以下两个例子来理解assert()的使用:
FILE *fp;
fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件
assert( fp ); //所以这里不会出错
fclose( fp );
fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败
assert( fp ); //所以这里出错
fclose( fp ); //程序永远都执行不到这里来
return 0;
int resetBufferSize(int nNewSize)
{
//功能:改变缓冲区大小,
//参数:nNewSize 缓冲区新长度
//返回值:缓冲区当前长度
//说明:保持原信息内容不变 nNewSize<=0表示清除缓冲区
assert(nNewSize >= 0);
assert(nNewSize <= MAX_BUFFER_SIZE);
}
应当注意:
每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败。
ASSERT 只有在 Debug 版本中才有效,如果编译为 Release 版本则被忽略。
不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题。
问题二 每日构建
+ 每日构建(Daily Build或者Nightly Build),就是每天都把整个软件项目自动编译一遍,最终生成的产出物必须和交付到用户手中的一样(比如你最终提交给用户的是一个安装程序,那就必须在开发过程中每天编译出一个安装包)。
+ 在微软软件开发中,每日构建是最重要的过程之一,被称为微软产品开发的“心跳”。简单来看,每天构建系统将整个产品解决方案完整构建一遍,生成的目标文件和安装文件被放置在一个共享位置。接着,安装文件被自动部署到release server上,随后可以自动运行BVT(build verification test),并将所有结果寄送每个team member的信箱。有一套完善的内部系统来完成整个自动化流程,以及流程管理、reporting等工作,而如果我们没有这套系统,也想实现完整的daily build流程,该怎么做呢?
+ 在VS.NET2003时代,IDE可以控制整个方案的构建,但是所有的构建逻辑被IDE控制,对于开发人员来说,整个构建流程就像一个黑箱,很难修改和管理。当然使用 PreBuildEvent和PostBuildEvent来控制,但是这些event都写在csproj/vbproj文件中,不便于修改,不适于扩展。而且使用IDE来做每日构建的话,要求构建系统本身装有VS.NET,这会带来额外的成本。另一种办法是使用NAnt,通过XML配置文件,来管理构建流程,这会使得整个流程易于修改,可扩展,并且不要求构建系统安装IDE,只需要有framework即可。问题是使用NAnt必须额外写一堆复杂的XML配置文件,足以让很多developer看了头疼。
+ VS.NET2005中引入了一套全新的构建系统:MSBuild。简单来讲,MSBuild可以直接读取csproj文件,控制csc/vbc等编译器,生成整个方案。实际上,VS2005的IDE自身就是调用MSBuild来完成编译的,这与VS2003有很大的不同。并且由于VS2005的csproj文件服从MSBuild的配置schema,因此我们可以直接使用csproj,稍稍修改一下,就能组织起完整的构建流程了。
问题三 项目Debug版本与Release版本的区别
-
Debug版本:通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
-
Release版本:称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
实际上,Debug版本和 Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。
问题四 代码覆盖率
-
代码覆盖(Code coverage)是软件测试中的一种度量,描述程序中源代码被测试的比例和程度,所得比例称为代码覆盖率。
-
代码覆盖程度的度量方式是有很多种的,这里介绍一下最常用的几种:
- 语句覆盖(StatementCoverage),又称行覆盖(LineCoverage),段覆盖(SegmentCoverage),基本块覆盖(BasicBlockCoverage),这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,因此就不会包括像C++的头文件声明,代码注释,空行,等等。只统计能够执行的代码被执行了多少行。需要注意的是,单独一行的花括号{} 也常常被统计进去。语句覆盖常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。
- 判定覆盖(DecisionCoverage)
又称分支覆盖(BranchCoverage),所有边界覆盖(All-EdgesCoverage),基本路径覆盖(BasicPathCoverage),判定路径覆盖(Decision-Decision-Path)。它度量程序中每一个判定的分支是否都被测试到了。这句话是需要进一步理解的,应该非常容易和下面说到的条件覆盖混淆。 - 条件覆盖(ConditionCoverage)度量判定中的每个子表达式结果true和false是否被测试到。
判定覆盖与 条件覆盖的区别:
int foo(int a, int b)
{
if (a < 10 || b < 10) // 判定
{
return 0; // 分支一
}
else
{
return 1; // 分支二
}
}
设计判定覆盖案例时,我们只需要考虑判定结果为true和false两种情况,因此,我们设计如下的案例就能达到判定覆盖率100%:
TestCaes1: a = 5, b = 任意数字 覆盖了分支一
TestCaes2: a = 15, b = 15 覆盖了分支二
设计条件覆盖案例时,我们需要考虑判定中的每个条件表达式结果,为了覆盖率达到100%,我们设计了如下的案例:
TestCase1: a = 5, b = 5 true, true
TestCase4: a = 15, b = 15 false, false
需要特别注意的是:条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个条件表达式的结果true和false测试到了就OK了。因此,我们可以这样推论:完全的条件覆盖并不能保证完全的判定覆盖。
4. 路径覆盖(PathCoverage),又称断言覆盖(PredicateCoverage)。它度量了是否函数的每一个分支都被执行了。 这句话也非常好理解,就是所有可能的分支都执行一遍,有多个分支嵌套时,需要对多个分支进行排列组合。
问题五 白盒测试
白盒测试又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,即清楚盒子内部的东西以及里面是如何运作的。"白盒"法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。"白盒"法是穷举路径测试。在使用这一方案时,测试者必须检查程序的内部结构,从检查程序的逻辑着手,得出测试数据。
白盒测试的分类:
(1)静态白盒测试
a.什么是静态测试?
不实际运行被测系统本身,检查文档内容、界面、代码规范等
b.静态白盒测试
不实际运行被测系统本身,检查和审查代码的设计、结构,也称为结构化分析
尽早发现程序中的缺陷,可以发现30%-70%的缺陷,可以为黑盒测试人员提供测试思路
c.静态白盒测试的策略(方法)
--桌前走查
--代码检查
--代码审查(人员:语言专家、行业专家、程序员、项目经理、测试人员)
--正式审查
d.审查单(Checklist):记录审查代码时或者公司内部整理的错误类型
(2)动态白盒测试
a.设计测试用例,根据测试用例执行被测程序(代码),验证代码的逻辑结构是否满足需求
b.设计测试用例的方法:
语句覆盖
判定覆盖
条件覆盖
判定+条件覆盖
条件组合覆盖
路径覆盖
基本路径测试方法