Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/242.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在PHP中对if语句进行单元测试_Php_Unit Testing_If Statement_Phpunit - Fatal编程技术网

如何在PHP中对if语句进行单元测试

如何在PHP中对if语句进行单元测试,php,unit-testing,if-statement,phpunit,Php,Unit Testing,If Statement,Phpunit,我目前正试图用一个if语句对get方法进行单元测试。我不知道如何去测试这个方法,我也没有发现多少有用的信息 /** * @var Info */ private $info = null; # Not pertinent information skipped public function getInfo() { if(!$this->Info) { $this->Info = InfoFacade::getInfoByToken($this->

我目前正试图用一个if语句对get方法进行单元测试。我不知道如何去测试这个方法,我也没有发现多少有用的信息

/**
 * @var Info
 */
private $info = null;

# Not pertinent information skipped

public function getInfo()
{
    if(!$this->Info) {
        $this->Info = InfoFacade::getInfoByToken($this->getToken());
    }

    return $this->Info;
}
然后在InfoFacade类中有一个函数,它获取一组信息并返回自身

我的理解是,我需要使用shouldreceive和shouldnotreceive,但我不确定是否应该使用数据提供程序,以及如何正确地将其应用于这种情况


我的问题是如何测试这样的if语句,如果数据提供程序是我认为最好的方式,那么如何正确设置数据提供程序?

单元测试的思想是,在测试之前有一个已知状态,在测试之后有一个预期状态。在这里,您希望状态仅在第一次调用
getInfo
时更改


要运行此测试,您将从
Info
null
的状态开始。然后,您可以调用该方法并检查返回的信息是否是您期望由facade返回的信息。然后更改外观中的内容并再次调用
getInfo
。返回的内容应该与第一次调用时的内容相同,而不是您将外观更改为的内容。

在介绍中给出的答案是正确的,我想添加另一个方面,特别是在阅读了您在下面的评论以及关于嘲弄的问题之后

您询问的是在公共方法中测试if语句

在这种情况下,if语句实际上是公共方法
getInfo()
的内部细节,这一点很重要,单元测试不应该真正关心实现细节。实现细节是,被测对象(SUT)将在第一次调用(延迟加载)时获取信息数据,并将其存储在内部以供将来参考

这意味着您拥有的公共接口是一些实现细节的包装器(对象获取数据的方式与对象本身无关,但与测试无关)

现在,正如您编写的一样,对于单元测试,您希望测试该方法中的所有路径。这需要调用该方法两次。在第一次通话中,您将返回数据,在第二次通话中,数据必须相同。所以从技术上讲,您所需要做的就是调用该方法两次来测试内部构件

$foo = new Foo();
$expected = $foo->getInfo();
$actual = $foo->getInfo();
$this->assertSame($expected, $actual);
然而,要测试单元,实际上只需调用该方法一次,就可以知道它可以正常工作,因为私有属性不会更改,因为它是私有的(正确封装的),并且您实际上不想关心是否使用该对象

因此,实际上有人可能会说您不想测试if子句,因为这是一个实现细节

注意:当您测量代码覆盖率时,您会看到单个调用已经覆盖了所有行(尽管不是所有路径都被单个调用覆盖)。这仅仅表明100%的覆盖率并不意味着您可以隔离地覆盖所有路径

我个人的理解是,对于单元测试来说,在测试中调用该方法一次并断言它不会返回NULL就足够了

$foo = new Foo();
$this->assertNotNull($foo->getInfo());
您可以通过更准确地断言您期望该方法返回的内容(例如,某些具体类型不只是非NULL),使这一点更加严格,但是对于单元测试来说,这应该已经足够了

这里的关键点是,首先测试SUT的公共接口。如果存在具有特定实现的回归,则只需要测试细节。这属于另一个测试,因此您可以在一年后删除它,b/c该测试仅用于修复回归,并且在一段时间后,应该不再需要

更好的是:对于正在使用的Facade,您可能希望测试Facade是否工作,即调用该全局函数并检查预期结果。这是针对该外观的另一个测试,而不是针对与其协作的对象

否则,您可以为了它而把事情模拟得死去活来,但最好在测试中保持简单,因为在编程中经常如此。否则,总是有过度设计的倾向,这可能会在测试中造成危害。你可能会把公共界面变成荒谬的东西,但你却想依赖它们。因此,信任他们是一种考验

作为附加说明,请考虑对测试进行测试,即使方法的实现细节改变。这可能是一个很好的描述,您希望随着时间的推移进行更改,如果更改没有改变任何(由单元测试指定的)意图,那么现有测试应该向您报告

另一方面注意:由于get上有initialize属性if null,因此也可以将其与PHP内联:

public function getInfo()
{
    return $this->Info 
        ?: $this->Info = InfoFacade::getInfoByToken($this->getToken());
}
或:

请参阅
=
、三元(第一个示例)或空合并运算符(第二个示例)(请参阅PHP手册了解所有这些)。有关最后两种方法的比较,请参见


这就是我对代码所做的<代码>//排列$mockInfoFacade=m::mock(“重载:”.InfoFacade::class)$mockToken=“token”$mockInfo=null//Act$mockPaymentFacade->shouldreceive(“getInfoByToken”)->with$mockToken->once()//Arrange但如果我理解正确,我将Info定义为null,然后需要使用“$this->assertEquals();”检查。但我无法改变正面返回的内容。我认为我没有能力做到这一点。这非常有帮助,帮助我完善了如何进行单元测试的思考过程。非常感谢。
public function getInfo()
{
    return $this->Info 
        ?? $this->Info = InfoFacade::getInfoByToken($this->getToken());
}