我很抱歉,因为我对软件测试很陌生。但是我有一个简单的代码来创建具有 100% 代码覆盖率的白盒测试用例:
01 public class ShapeAreas {
02
03 public double oneParameter(String shape, float x1)
04 {
05 float area;
06 if (shape.equals("A"))
07 return x1 * x1 * Math.XI;
08 else if (shape.equals("B"))
09 return x1 * x1;
10 else
11 return -1.0;
12 }
13
14 public double twoParameter(String shape, float x1, float x2)
15 {
16 float area;
17 if (shape.equals("N"))
18 return x1 * x2;
19 else if (shape.equals("M"))
20 return 0.5 * x1 * x2;
21 else
22 return -1.0;
23 }
24 }
我需要有关我的输入数据在此代码上的外观的帮助,以便以最少的测试用例数量实现 100% 的代码覆盖率。
我很感激我能得到的任何帮助,谢谢!
我冒昧地在您的代码中添加行号,以便能够给出更好的解释。 您在评论中提到您对声明覆盖范围感兴趣。 代码示例中的语句位于第 07、09 和 11 行以及第 18、20 和 22 行中。 当然,if
语句本身也是语句(因此得名),但无论如何,这些语句都会在每次执行相应函数时执行。
在函数oneParameter
的一个执行中,将只执行一个条件语句:在第 07 行、第 09 行或第 11 行。 这是因为if-else if-else
声明的排他性。 类似地,在对函数twoParameter
的一次调用中,将执行第 18 行、第 20 行或第 22 行中的语句。
因此,要涵盖所有语句,您必须调用每个函数三次。 在这两种情况下,控制实际分支的参数都是shape
参数。 这意味着,其他参数的值与将执行哪个语句无关。 一组简单的调用可能是:
oneParameter("A", 0.0);
oneParameter("B", 0.0);
oneParameter("any other", 0.0);
twoParameter("N", 0.0, 0.0);
twoParameter("M", 0.0, 0.0);
twoParameter("any other", 0.0, 0.0);
这是实现 100% 语句覆盖率的最小调用集的示例。 可能令人惊讶的是,这些只是电话——甚至没有对结果进行任何评估。 当我们谈论测试覆盖率时,隐含的假设是,相应的代码行不仅被执行,而且相应的结果作为测试的一部分进行评估。 这可能如下所示:
assertEquals(0.0, oneParameter("A", 0.0));
assertEquals(0.0, oneParameter("B", 0.0));
assertEquals(-1.0, oneParameter("any other", 0.0));
assertEquals(0.0, twoParameter("N", 0.0, 0.0));
assertEquals(0.0, twoParameter("M", 0.0, 0.0));
assertEquals(-1.0, twoParameter("any other", 0.0, 0.0));
尽管现在它具有100%的语句覆盖率并且还可以对结果进行评估,但它仍然远非高质量的测试套件。 原因如下:执行单元测试的主要目标是查找代码中的错误。 然而,上面的一组测试并不适合发现任何有趣的错误。 为您提供一些此测试套件找不到的可能错误的示例:
- 错误地交换了函数
oneParameter
中"A"
和"B"
的计算。 - 在
"N"
的功能twoParameter
中,操作*
被错误地交换了+
。 - 在函数
twoParameter
中,"N"
,表达式不是将x1
乘以x2
,而是将x1
乘以x1
。 - 在函数
twoParameter
中,"M"
常量设置为0.05
而不是正确的0.5
。
这些只是可能的错误示例。 因此,认真对待查找可能的错误的目标需要超越覆盖范围。 事实上,甚至可能有一些代码部分根本不适合使用单元测试进行测试 - 尽管在您的简单示例中并非如此。 此类代码部分的示例是无法访问的代码(例如,为健壮性而添加的switch语句的默认分支),或者仅包含与其他组件的交互的代码,在这种情况下,集成测试是更适合的方法。 因此,达到 100% 覆盖率的目标通常没有意义,即使您真诚地追求一个高质量的单元测试套件。
尽管如此,对于有兴趣确保他们已在其代码中解决所有相关方案的开发人员来说,覆盖率是一个有价值的信息。 可悲的是,从管理角度判断测试套件的质量时,覆盖率的价值要低得多:在这种情况下,覆盖率通常减少到仅百分比,开发人员被迫创建测试,直到达到一定的覆盖率 - 但通常足够没有给他们足够的培训,时间和鼓励来正确进行测试。 因此,为了达到80%的覆盖率,所有琐碎的代码(getter和setter等)可能会被"测试"以增加覆盖率。 然而,由于时间不够,对最复杂和最难测试的 20% 代码的测试被推迟(尽管这可能是隐藏错误的代码)。 而且,即使是已经覆盖的 80% 也可能像我上面展示的最小测试套件一样测试得很糟糕。
您必须在每种方法中查找分支才能获得 100% 的覆盖率。 它是A
、B
、X
作为oneParameter
方法的shape
参数,N
、M
、X
twoParameter
方法的参数。
每种方法的 3 个测试用例将为您提供 100% 的覆盖率。
但是,它不会告诉您您的代码是 100% 正确的。
尝试例如null
形状。(这将导致NullpointerException
)
您还需要定义计算所需的精度。(double
返回类型与浮点数计算。
public void testOneParameterWithShapeB() {
double result = sut.oneParameter("B", 1.0);
//TODO check the result
}