谷歌搜索“软件测试理论”似乎只是给出了软词义的理论。我没有找到任何可以归类为数学,信息理论或其他科学领域意义上的理论的东西。
我正在寻找的东西可以形式化什么是测试,使用的概念,什么是测试用例,测试某物的可行性,测试某物的实用性,应该测试某物的程度,形式的定义/解释代码覆盖率等
更新:另外,从直觉上讲,我不确定形式验证与我所要求的内容之间是否存在联系,但是显然存在某种联系。
(a,b)=>a/b
,该函数需要使用溢出值进行扩展才能正确组合。
谷歌搜索“软件测试理论”似乎只是给出了软词义的理论。我没有找到任何可以归类为数学,信息理论或其他科学领域意义上的理论的东西。
我正在寻找的东西可以形式化什么是测试,使用的概念,什么是测试用例,测试某物的可行性,测试某物的实用性,应该测试某物的程度,形式的定义/解释代码覆盖率等
更新:另外,从直觉上讲,我不确定形式验证与我所要求的内容之间是否存在联系,但是显然存在某种联系。
(a,b)=>a/b
,该函数需要使用溢出值进行扩展才能正确组合。
Answers:
对于一本探索软件测试背后的数学的书...要获得的精髓是计算机系统性能分析的艺术:实验设计,测量,仿真和建模技术
尽管该书于1991年首次出版,但由于它是一本应用数学书,只专注于性能分析,仿真和测量,因此至今仍很流行。
我无法指出一个好的在线资源(有关这些主题的英文Wikipedia文章往往是可改进的),但是我可以总结一下我听到的一个演讲,其中也涵盖了基本的测试理论。
有不同种类的测试,例如单元测试或集成测试。单元测试断言,一条连贯的代码段(函数,类,模块)按预期的独立工作,而集成测试断言,多个这样的代码段可以正确地协同工作。
测试用例是一种已知的环境,其中例如通过使用特定的测试输入或通过模拟其他类来执行一段代码。然后将代码的行为与预期行为(例如特定的返回值)进行比较。
测试只能证明存在错误,而不能证明所有错误。测试为程序的正确性设定了上限。
为了定义代码覆盖率度量,可以将源代码转换为控制流程图,其中每个节点都包含代码的线性段。控制仅在每个块的末尾在这些节点之间流动,并且始终是有条件的(如果有条件,则转到节点A,否则转到节点B)。该图具有一个起点和一个终点。
因此,检查条件覆盖率通常很有用。
true
和false
。这意味着完全的分支机构覆盖范围,但是相当昂贵。该程序可能具有排除某些组合的其他约束。该技术非常适用于获取分支覆盖,可以找到无效代码,但无法找到由于错误条件而导致的错误。使用条件覆盖构建测试输入时,应考虑短路。例如,
function foo(A, B) {
if (A && B) x()
else y()
}
需要使用foo(false, whatever)
,foo(true, false)
和进行测试,以foo(true, true)
实现最小的多重条件覆盖。
如果您的对象可能处于多种状态,那么测试所有类似于控制流的状态转换似乎是明智的。
有一些更复杂的覆盖率指标,但是它们通常与此处介绍的指标相似。
这些是白盒的测试方法,并且可以部分地自动化。请注意,单元测试套件应以任何选择的指标为目标,以具有较高的代码覆盖率为目标,但并非总是100%可行。在必须将故障注入到特定位置的情况下,测试异常处理尤其困难。
然后有一些功能测试,它们通过将实现视为黑盒来断言该代码符合规范。这样的测试对于单元测试和集成测试都非常有用。因为不可能用所有可能的输入数据进行测试(例如,使用所有可能的字符串测试字符串长度),所以将输入(和输出)分组为等效类很有用-如果length("foo")
正确,foo("bar")
则也可能工作。对于输入和输出对等类别之间的每种可能组合,至少要选择一个代表性输入并进行测试。
一个应该另外测试
length("")
,foo("x")
,length(longer_than_INT_MAX)
,length(null)
,以及length("null byte in \x00 the middle")
...使用数字表示测试0, ±1, ±x, MAX, MIN, ±∞, NaN
,而使用浮点比较测试两个相邻的浮点数。另外,可以从等效类中选择随机测试值。为了简化调试,值得记录使用的种子…
一款软件具有非功能性要求,这些功能也必须经过测试。这些包括在定义的边界(负载测试)以及超出边界的测试(压力测试)。对于计算机游戏,这可能是在负载测试中声明每秒的最小帧数。可能会给网站进行压力测试,以观察预期的响应时间是两倍多的预期访问者正在殴打服务器。这样的测试不仅与整个系统相关,而且与单个实体相关–哈希表如何随着一百万个条目而降级?
其他类型的测试是对场景进行模拟的整个系统测试,或者是证明已满足开发合同的验收测试。
有一些非测试技术可用于质量保证。例如演练,正式代码审查或结对编程。尽管某些零件可以自动化(例如使用短绒),但这些零件通常很耗时。但是,由经验丰富的程序员进行的代码审查会发现错误的比率很高,并且在无法进行自动测试的设计过程中特别有价值。
当代码审查如此出色时,为什么我们还要编写测试?测试套件的最大优势在于,它们可以(大部分)自动运行,因此对于回归测试非常有用。
正式验证可以证明代码的某些属性。手动验证对于关键部分来说最可行,而对整个程序则不太可行。证明为程序的正确性设定了下限。证明可以在一定程度上实现自动化,例如通过静态类型检查器。
某些不变量可以通过使用assert
语句进行显式检查。
所有这些技术都有自己的位置,并且是互补的。TDD预先编写了功能测试,但是一旦实现代码,就可以通过其覆盖率指标来判断这些测试。
编写可测试的代码意味着编写可单独测试的小型代码单元(具有适当粒度的帮助功能,单一职责原则)。每个函数采用的参数越少越好。这样的代码也适合于通过例如依赖注入来插入模拟对象。
也许“基于规范的测试”也可以回答您的问题。检查这些测试模块(我还没有使用过)。它们要求您编写数学表达式来指定测试值集,而不是使用所选的单个数据值编写单元测试。
正如作者所说,此Perl模块的灵感来自Haskell的Quick-Check模块。此页面上还有更多链接,其中一些链接已失效。
一种基于数学的方法是全对测试。这个想法是,大多数错误是通过单个配置选项选择激活的,而其余大多数是通过同时采用的一对特定选项激活的。因此,大多数可以通过测试“所有对”来捕获。这里有一个数学解释(带有概括):
(还有更多此类参考文献)
使用了一些数学方程式,但这取决于您使用的软件测试的类型。例如,关键故障假设假设故障几乎不是两个或多个同时故障的乘积。下式为:f = 4n + 1。f =为给定数量的变量(n) + 1计算测试用例数量的函数,其中所有变量均取标称值的常数1的加法。
另一种需要数学方程式的测试是“稳健性测试”,它是在测试过程中测试测试用例的稳健性或正确性。在此测试中,您将输入合法输入范围内的变量(干净的测试用例),并在输入范围外输入变量(脏的测试用例)。您将使用以下数学方程式:f = 6n + 1。 6n表示每个变量必须假定6个不同的值,而其他值假定标称值。* + 1 *表示常数1的加法。
double pihole(double value) { return (value - Math.PI) / (value - Math.PI); }
我从我的数学老师那里学到了。这段代码恰好有一个漏洞,仅凭黑盒测试无法自动发现。在数学中没有这样的漏洞。在微积分中,如果单边限制相等,则可以封闭孔。