【发布时间】:2019-03-03 14:26:27
【问题描述】:
我有一个调用内置 PHP 函数的方法,openssl_random_pseudo_bytes。
public function generateRandomBytes()
{
$crypto_secure = TRUE;
// $crypto_secure is passed by reference and will be set to FALSE by
// openssl_random_pseudo_bytes if it uses an insecure algorithm
$random_bytes = openssl_random_pseudo_bytes(16, $crypto_secure);
if (!$crypto_secure)
{
throw new Security_Exception('Random bytes not generated by a cryptographically secure PRNG algorithm');
}
return $random_bytes;
}
我有一个 PHPUnit 测试用例来测试这个方法(它所做的只是验证随机生成的字符串是 16 字节长)。
public function testRandomBytesLength()
{
$myclass = new MyClass();
$this->assertEquals(16, strlen($myclass->generateRandomBytes()));
}
我的问题是,我如何测试 $crypto_secure 为 FALSE 并且必须抛出异常的情况?由于这个值是作为对openssl_random_pseudo_bytes 的引用传入和修改的,所以我不确定如何获得这个执行路径的测试覆盖率。我的第一个想法是,也许我可以使用 php.ini 配置来强制 openssl_random_pseudo_bytes 使用加密不安全的算法(在测试用例中通过 ini_set)。有什么建议吗?
【问题讨论】:
-
单元测试是一个黑盒。你不应该关心一个类在内部做什么。使用
crypto_secure是调用的配置,但您的MyClass正在抽象它的使用。你不测试配置/内部。您将crypto_secure设置为 true。为什么你会在你的情况下将它设置为 false ?只是为了一个人为的测试用例?你能解释一下你想测试什么吗?因为这读作 xy 问题。 -
@k0pernikus 我不确定你的意思?
crypto_secure不是调用的配置,它是 openssl_pseudo_random_bytes 用来通知调用者它是否使用安全算法生成随机字节的标志。如果用于生成随机数的算法不安全,openssl_pseudo_random_bytes 会将$crypto_secure设置为FALSE。 -
我的错,我把它当作函数参数来读。现在我明白了为什么你将它作为变量传递,然后想要检查它。我仍然认为您不需要为您的检查创建单元测试。只需抛出异常就可以了。话虽如此,这也是为什么副作用不利于单元测试的典型例子。
-
@k0pernikus 这是一个容易犯的错误,因为它不是 PHP 中的常见模式(我的一位同事在代码审查期间也有同样的困惑 :) 是的,我同意这是一个非常糟糕的模式.希望未来版本的 PHP 将有一个对 TDD 更友好的替代方案
标签: php unit-testing random phpunit pass-by-reference