如何对这样的东西进行单元测试?

时间:2017-02-21 09:25:25

标签: php unit-testing phpunit code-coverage

我有一个基于Laravel密钥生成器的示例:

public function generateRandomKey(): string
{
    $generatedKey = base64_encode(random_bytes(16));

    // Encrypt the generated key with our public key so it is not a 'plain password' anymore.
    $value = openssl_public_encrypt($generatedKey, $crypted, $this->getPublicKey());

    if (!$value) {
        throw new \RuntimeException('Encryption failed: could not generate a random key.');
    }

    return base64_encode($crypted);
}

我想对此进行单元测试,我可以期待RuntimeException。我希望100%的代码覆盖率,但我也不想强迫方案只是为了获得100%的代码覆盖率。

在这个例子中,我也希望PHPUnit能够触及异常。我无法提供错误的密钥,因为我的getPublicKey()是私有的,并且在我遇到此方法中的错误之前会抛出错误。

触发解密错误并不难,因为我只能提供一个未正确加密的随机值。

那么我如何能够测试这样的场景并实现100%的代码覆盖率。测试这样的东西是可能的,甚至是明智的,还是应该用PHPUnit注释或其他什么来忽略它?

干杯。

2 个答案:

答案 0 :(得分:1)

如果100%的覆盖率是您的目标,那么您将需要沿着潜在的路线前进,而不是优化"你的代码是为了它。在这种情况下,它不会太受欢迎。

一种选择是将加密线抽象为它自己的部分可模拟方法,但是通过这样做(并告诉PHPUnit它将返回什么),你基本上只是检查可以抛出异常(字面意思)。

从语义上讲,getter / setter方法往往是公开的 - 而这并不是由任何机构严格执行的。我完全可以理解为什么您不希望getPrivateKey作为API的一部分,但可以可行地向您的公共API添加setPrivateKey方法 - 这将解决你的单元测试问题:

# File: YourClass
public function setPrivateKey(string $key) : YourClass
{
    $this->privateKey = $key;
    return $this;
}

然后:

# File: YourClassTest
/**
 * @expectedException RuntimeException
 * @expectedExceptionMessage Encryption failed: could not generate a random key.
 */
public function testGenerateRandomKeyThrowsExceptionWhenCannotEncrypt()
{
    $class = new YourClass;
    $class->setPrivateKey('highly-unlikely-to-be-a-valid-private-key');
    $class->generateRandomKey();
}

当然 - 通过这样做,您会遇到这样的争论:"您不应该测试您不拥有的代码,即openssl方法。如果这是您的目标,那么您可以通过权衡取得100%的覆盖率。

答案 1 :(得分:0)

您需要将openssl_public_encrypt存根以返回false。

假设您的generateRandomKey方法属于类StephanV,则测试可能如下所示:

namespace Tests;

function openssl_public_encrypt()
{
    return false;
}

class StephanVTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @expectedException \RuntimeException
     */
    public function testGenerateRandomKeyThrowsException()
    {
        $cut = new StephanV;
        $cut->generateRandomKey();
    }
}