使用 private/protected 常量测试 class

Testing class with private/protected constant

在测试 class 方法时,有时我需要将返回值与某些 class.

中定义的常量进行比较
class FooBar
{
    const RANDOM = 18;
}
....
// Somewhere in test...
$this->assertEquals(FooBar::RANDOM, $mock->doSomething());

从 PHP 7.1 开始,可以使用可见性修饰符定义 class 常量,这可以更改为:

private const RANDOM = 18;

但是,这会阻止测试工作,因为现在我们正在尝试访问私有常量。

所以现在我们有两个选择:

  1. 将常量声明为 public。
  2. 在测试中使用反射。意味着测试变成:

$this->assertEquals( (new ReflectionClass(FooBar::class))->getConstant('RANDOM'), $mock->doSomething() );

第一种方法感觉很不对,因为我们只是为了测试而设置常量 public,而不是因为 class/hierarchy/business 模型需要它是 public.

第二个感觉也不对,因为找不到这个用例 任何 IDE,所以任何 search/replace/refactor 在这里都会失败。

所以我的问题是,是否应该在不关心重构会破坏测试的情况下使用第二种情况?或者甚至应该不鼓励在断言中使用常量?

恕我直言,在测试中使用常量实际上是一种不好的做法。

您应该测试常量的字面值。 ($this->assertSame(18, $mock->doSomething())

为什么?

因为测试带给您的重要价值之一是您注意到代码更改的意外后果。由于常量是私有的,因此它的值永远不会在 class 之外使用。但是许多不同的事情可能取决于它的内部价值。

现在想象一个不熟悉代码库的初级开发人员的任务是更改其中一个使用常量的地方并将其从 18 更改为 16。他将把常量的值从 18 更改为16 并粗略检查常量的使用位置(不要注意您的 doSomething() 方法)。现在,在您的方法中,您绝对需要随机数为 18,而不是 16!但如果你使用常量,他永远不会知道,因为当他将它从 18 更改为 16 时,断言也会从 18 更改为 16。测试将通过。

我的经验法则:

Never use expected value of assert that is pulled from the code of the app. Always use literal value where possible.