您是否在测试用例中使用了实现中的常量?

时间:2010-07-29 06:46:39

标签: unit-testing constants

假设你有一些像这样的代码(在一个成熟的语言中,因为这个问题无关紧要):

constant float PI = 3.14;
float getPi() 
{ 
   return PI;
}

你会这样测试一下:

testPiIs3point14()
{
   // Test using literal in test case
   AssertEquals( getPi(), 3.14 );
}

或者像这样:

testPiIs3Point14()
{
   // Test using constant from implementation in test case
   AssertEquals( getPi(), PI );
}

换句话说,您是否在测试用例中使用被测系统中的常量?或者这被视为实施细节?

6 个答案:

答案 0 :(得分:17)

这两项测试有不同的用途。

第一个确保getPi()将始终返回3.14。它涵盖常量和函数,如果有人发现软件中使用的PI值不够准确并用3.14159替换它,则会失败。这可能是好的,也可能是坏的,具体取决于具体情况。

虽然第二种形式仅涵盖功能。如果有人改变常数,它不会失败;只有在修改函数以返回另一个常量(具有不同的值)时,它才会失败。

两者之间的选择取决于测试的目标。如果常量必须永远不变,请使用文字。使用常量来确定函数的行为:返回一个常量 - 无论其值如何。在第二种情况下,测试可能是不必要的。

答案 1 :(得分:6)

我一直在寻找有关同一主题的信息。到目前为止,我的结论是你不应该使用文字,但你也应该确保常数是你所期望的。

如果您在10个不同的单元测试中使用了文字,并且由于任何原因更改了值,那么您必须更改所有10个文字中的值。您可以或者示例需要为PI添加更多精度。

最好的替代方案是实施单元测试以检查常量值是否符合预期,然后在其他测试中自由使用常量。

实施这两项测试的方法:

testPiIs3point14()
{
   AssertEquals( PI, 3.14 );
}

testGetPiReturnsPi()
{
   AssertEquals( getPi(), PI );
}

PS:虽然检查值对于所有常量可能并不那么重要,但对某些常量来说可能非常重要。我能想到的一个例子是包含URL或类似值的常量。

答案 2 :(得分:3)

我认为这是关于测试和生产代码之间的耦合的问题。当我第一次启动TDD时,我认为在测试中使用常量可以使测试更加彻底。但是,现在我认为它只会导致测试和实现之间更紧密的耦合。如果将常量复制并粘贴到测试中,是否会使其更安全?并不是的。它只会让更改常量变得更加痛苦,特别是如果将其复制粘贴到多个测试中。这些测试不测试它是否是正确的常量,它们只测试从方法返回的这个常量,所以现在我肯定会选择第二个测试。

答案 3 :(得分:2)

我认为这里有两个截然不同的案例:

  1. 如果您正在测试一个对计算结果至关重要的常量,就像在您的示例中一样,我认为最好使用独立测试,而不是重复使用您尝试的代码中的相同常量去测试。我不会直接测试常量值,而是测试(例如)函数CalculateAreaOfCircle(),它将验证Area公式是否正确并同时验证PI的值。

  2. 我认为重用枚举和其他不直接影响代码关键部分结果的常量是有意义的。

答案 4 :(得分:1)

绝对是第二种形式,常数的目的是不引入“幻数”。现在,在单元测试中,你倾向于使用魔术数字,这没关系。

在这种情况下,您引入了一个常量AND使用了一个幻数。我要么在任何地方使用常量,要么根本不使用它。

答案 5 :(得分:1)

我使用第一种形式 - 即使它复制了值(仅两次),它更具可读性。

[Test]
public void GetPIReturns3_14()
{
  Assert.AreEqual(3.14, testSubject.GetPI());
}

复制是必要的,因为如果你在第二次测试中重复使用常量,那么你并没有真正测试任何东西。实际上,您正在测试“Is Constant == Constant?”。这个测试永远不会失败。例如如果我将PI更改为1010.1010,则第二次测试不会失败。