2012-12-03 26 views
2

这是一个超级简单的例子,在C这里,来说明一个微妙的错误,我不知道如何公开通过测试的错误。如何设计软件测试的细微的错误

考虑:

#include <stdio.h> 

int main() 
{ 
    int a; 
    int b; 
    int input; 

    printf("Enter 1 or 2: "); 
    scanf("%d", &input); 

    switch(input) { 
    case 1: 
    a = 10; 
    /* ERROR HERE, I FORGOT A BREAK! */ 
    case 2: 
    b = 20; 
    break; 
    default: 
    printf("You didn't listen!\n"); 
    return 1; 
    break; 
    } 

    if(input == 1) { 
    b = 30; 
    printf("%d, %d\n", a, b); 
    } else { 
    printf("%d\n",b); 
    } 

    return 0; 
} 

正如代码所指出的,一个break缺少这样输入的时候1,它属于通过对病例2 1的输出,虽然它覆盖b没有反映这后来。因此,我们可以设计的所有测试,例如通过输入来自集合{1, 2, 10}的数字,都会产生正确的输出。

在现实中,switch里面的分配可能会非常昂贵,所以这种错误可能是相当昂贵的。但是,假设从第一天开始就是这样写的,没有基准来看到成本高于预期。

那么,什么可以做,以冲洗掉这些类型的错误?有没有办法设计测试用例以在生产软件中公开它?

编辑 所以我想我并不完全清楚 - 我写在C来说明类型中遇到的问题,但实际上它不是具体到C.我想点make是代码进入我们从未打算进入的部分(在这种情况下是因为忘记了break来说明这一点)。我的实际情况是Fortran代码有700,000行,它正在进入我们从未打算过的分支机构,因为从语言的角度来看这是合法的,但是可能非常昂贵。

是否有可能设计一个测试或从某个工具看一些数据,它会告诉我们它将进入不应该的分支?我通过打印“我不应该在这里!在所有的案例中,看到它被打印出来,那么比随机查看和放置打印语句更好。

回答

1

您可以定义switch语句编码约定,从而使每个分支将对一种特殊状态。就像一个变量分配了这个案例的值。例如:

switch (v) { 
case 1: 
    vcheck = 1; 
    ... 
    break; 
case 2: 
    vcheck = 2; 
    ... 
    break; 
} 

和测试vcheck在你的测试用例。

除此之外,您可以使用执行静态代码分析验证MISRA rules的工具 - 并将它们引入您的构建过程。他们会诱发一些一片心意... :-)

最后,(我的最爱),你可以写一个脚本来检查此类情况,并警告他们agains。

1

情况1的正确状态是b不会被设置。

检查是否设置了b。

您可能需要向下打破你的代码分成小段,以测试这一点,如果你以后设置b,但是这只是良好的模块化。

好像你问“我怎么测试无法验证码?”。答案是,编写可测试的代码需要技巧和计划,但不能只是事后的想法。

有在网络上吨的东西来帮助你编写测试代码:

https://www.google.com/search?q=writing+testable+code

0

如果input==1,你会看到b = 30的输出,你就知道什么是错的。另外,请记住else子句,在读取它之前,你应该写一些b。在default:的情况下(例如,input==100),您最终可能会从某个位置进行读取而未正确设置它。

此外,代码审查,如果你能负担得起,应该大大有助于找到像这样的事情。

+0

这个具体的例子,你会期望在case 1的输出中看到'b = 30',事实上你会看到'b = 30'。无论如何,C的选择只是为了说明我试图提出的观点。我更新了这个问题来澄清。 – tpg2114

1

对于您的具体示例,它绝不是定义中的错误/错误。语言中通缉的可能性。如果你想禁止某些危险的语言功能,那么linters是要走的路。

完全避免不可预见的错误,有一个规则:始终防御性代码,并利用assert小号等。无论您可以把它们。

+0

我更新了这个问题 - C语言的使用只是为了说明一种问题,但它确实比这更一般。我可以用Fortran编写这个例子,但想法C会更宽泛地理解。但是你的回答对于这个具体的例子来说绝对正确。 – tpg2114

1

为什么这是我问的一个错误?使用任何类型的黑盒测试代码工作。所以,如果唯一的要求是代码的工作,那么没有错误。

但代码有缺陷。缺少break会使代码更难以理解和难以维护。

编码约定是关于代码外观的规则。遵守编码约定不能通过测试编译的程序来完成,它们必须在源代码上完成。

测试编码约定通过代码检查(自动或手动)完成。

编辑:

如果你担心性能,然后使用仪器工具来寻找“热点”。你会发现大部分的执行时间可能只用在几个模块中。查看这些模块以及每次打电话给他们。你会发现你只需要查看10-30 000行代码。由于评审范围有限,评审应持续1-3周。

底线:当涉及到发现细微的错误时,代码评审远远优于测试。

+0

在这种情况下,它不是一个“错误”,因为它没有副作用,分配也不贵。但如果它很昂贵(但是我们没有看到突然跳跃的基线,因为从第一天开始就是这样)?在这种情况下显然是不受欢迎的。是否有方法或数据可用于检查通过代码的意外路径?显然它可能需要一个人来介入和分析数据,但这比通过近一百万行代码更容易。我添加了更多的信息来澄清问题。 – tpg2114

+0

使用测试来发现细微的错误是非常困难的。见上面的编辑。 –