单元测试:给出一个不破坏PHP的无效数组键。可能的

单元测试:给出一个不破坏PHP的无效数组键。可能的,php,arrays,unit-testing,phpunit,array-key,Php,Arrays,Unit Testing,Phpunit,Array Key,我正在为一个小班做单元测试。我正在使用这个类来处理PHPUnit,这样我就可以开始正确地测试我将来编写的更大的代码了 考虑我正在尝试测试的以下代码: /** * Registers a starting benchmark tick. * * Registers a tick with the ticks registry representing the start of a benchmark timeframe. * * @param string $id The identif

我正在为一个小班做单元测试。我正在使用这个类来处理PHPUnit,这样我就可以开始正确地测试我将来编写的更大的代码了

考虑我正在尝试测试的以下代码:

/**
 * Registers a starting benchmark tick.
 *
 * Registers a tick with the ticks registry representing the start of a benchmark timeframe.
 *
 * @param string $id The identifier to assign to the starting tick.  Ending tick must be the same.
 * @return bool Returns TRUE if a tick was registered successfully or FALSE if it was not.
 * @since 0.1
 */
public function start($id)
{
    $this->tick($id . "_start");
    if($this->getStart($id) != false) {
        return true;
    }
    return false;
}

/**
 * Retrieves a registered start tick.
 *
 * Checks to see if a start tick is registered.  If found the microtime value (as a float) is
 * returned, otherwise FALSE is returned.
 *
 * @param string $id The identifier to lookup the tick under.
 * @return mixed The microtime (as a float) assigned to the specified tick or FALSE if the tick
 * start hasn't been registered.
 * @since 0.1
 */
public function getStart($id)
{
    if(isset($this->ticks[$id . "_start"])) {
        return $this->ticks[$id . "_start"];
    }
    return false;
}
以下是实际测试代码:

public function testBadStartTick()
{
    $this->assertFalse($this->bm->start("What_Invalid_Key_Fits_Here?"))
}
问题是这个测试函数总是返回true,不管我尝试使它返回false多少次。我尝试过给出空值、300多个字符的键、空数组,甚至是一个新对象的实例。在所有情况下,PHP要么中断,要么抛出某种警告。当PHP没有中断时,我的值将转换为PHP将在数组键中接受的值,然后在尝试执行$this->assertFalse时,我的测试不会通过

我希望实现尽可能高的代码覆盖率

所以我的问题是,给定这些方法的当前代码,它们在正常操作下是否会返回false

我在想,因为我是为了管理目的而添加文本的,所以我总是提供某种类型的密钥,无论我以$id的价格提供什么,PHP都会接受

有什么想法吗


提前谢谢

如何编辑代码,在使用前验证start接收到的数据

public function start($id)
{
    if ($id !== null) { // perhaps more validation is needed?
        $this->tick($id . "_start");
        if($this->getStart($id) != false) {
            return true;
        }
    }

    return false;
}

public function getStart($id)
{
    if(isset($this->ticks[$id . "_start"])) {
        return $this->ticks[$id . "_start"];
    }
    return false
}
然后您可以像这样进行测试:

public function testBadStartTick()
{
    $this->assertFalse($this->bm->start(null))
}

您将需要使用mock来执行此操作

这将需要你做这两个部分,以获得全面覆盖

但你必须这样做

public function testBadStartTick()
{
    $bm = $this->getMock('bm', array('getStart'));

    $bm->expects($this->any())
         ->method('getStart')
         ->will($this->returnValue(false));

    $this->assertFalse($bm->start("What_Invalid_Key_Fits_Here"))
}
当然,如果需要,用名称空间替换实际类名的bm。 这样,您将仅针对该测试模拟getStart的功能,并且您可以测试您的结果

当然,如果你想要全覆盖,测试你需要的一切

public function testGoodStartTick()
{
    $this->assertTrue($this->bm->start("What_Invalid_Key_Fits_Here"))
}
如果一切顺利,这将测试路径。因为您不再在那里模拟,它将使用实际的getStart函数

public function testMissingStartTick()
{
    $this->assertFalse($this->bm->getStart("What_Invalid_Key_Fits_Here"));
}
这将独立于其他函数测试getStart,因此该键将不存在并返回false

您不必单独测试真实路径,因为您将使用testGoodStartTick测试它

编辑:
正如人们在评论中所说的,我应该在这里提出警告,拥有永远不会执行的代码是不明智的。当你在那里检查时,我认为tick可能会产生一些魔力,有时不会将密钥添加到数组中,但我从你的评论中了解到情况并非如此。因此,在您的情况下,我的答案确实不正确,最好按照建议删除代码,您知道这些代码永远是正确的。

谢谢您的回复。我正在寻找一个不涉及编辑代码的解决方案。如果我所追求的是不可能的,那么我可以简单地返回值,因为它不是真正需要的。我相信你所追求的是不可能的,因为串联会导致$id被转换为字符串。谢谢。看来这让我走得更远了。我现在唯一的问题是,我得到的返回值是null,而不是false。有什么想法吗?@cracketastic我为你更新了答案。问题是你们需要一个局部模拟。当您向getMock添加一个以函数名作为第二个参数的数组时,它将只模拟那些函数,否则它将模拟一切运行良好的函数,非常感谢!我在PHPUnit网站上查找API参考,但乍一看,我只看到一本包含各种用例场景的手册。如果你想阅读模拟,你可以做更多的事情,也许我遗漏了一些东西,但代码永远不会返回false,因为在调用getStart之前,密钥总是设置好的,因此,对我来说,模拟对象使getStart返回false是没有意义的。你不是在测试对象,只是在改变它的工作方式。勾号方法实际上是做什么的?这就是你问题中缺失的谜题。如果您在测试中调用start,我们无法看到整个代码路径,因为此方法中可能会发生任何情况。包括使测试用例无法成功运行的代码。例如,如果tick在ticks[]数组中注册了该键,则对start的调用将永远不会返回false,模拟将模拟不存在的现实。在这种情况下,整个if都过时了,您可以始终返回true。@Sven这就是$this->tick的全部功能,这也是我提出问题的部分原因。我很好奇,是否有可能为PHP提供一个不能用作数组键的值,但不会同时让PHP屈服。如果这是不可能的,那么我已经在想你已经触及的,是真的,我永远不能从$this->start中得到false。因此,最终的解决办法是在我的测试中放弃模拟对象,并删除if.PHP将总是尽可能地接受变量作为数组键,或者致命地失败。请注意,仅包含数字的字符串将始终转换为 整数。如果您想验证是否传递了一个有效值作为键,那么您必须在代码中亲自验证以避免致命错误,例如If is_string$id{/*add to array*/},这将产生不同。