at匹配器弃用后重写PHPUnit测试

问题描述

我曾经有过这样的PHPUnit代码(由于我无法重写它,可能不是一个代码):

$authorizator->expects($this->at(0))
    ->method('isAllowed')
    ->willReturn($hasSuperPrivilege);

if (!$hasSuperPrivilege) {
    $authorizator->expects($this->at(1))
        ->method('isAllowed')
        ->willReturn($hasstandardPrivilege);
}

在弃用at()方法后如何实现相同的行为?

我不知道该方法将被调用多少次,所以willReturnOnConsecutiveCalls方式可能不合适吗?

如果第一次调用返回false,则isAllowed()方法必须调用两次,如果返回true,则只能调用一次。

相关问题:https://github.com/sebastianbergmann/phpunit/issues/4297

经过测试的方法

public function canUserdoSomething(Foo $resource,Identity $identity): bool
{
    if (
        $this->authorizator->isAllowed(
            $identity,$resource,'superPrivilege'
        )
    ) {
        return true;
    }

    if (
        $this->authorizator->isAllowed(
            $identity,'standardPrivilege'
        )
    ) {
        return $resource->hasSomeproperty();
    }

    return false;
}

解决方法

我会带手写的假冒品,所以您不必担心打来的电话。为了简洁起见,我在示例中内联了代码,但是如果您在多个测试中使用authorizator,则将其提取到一个单独的类中是很有意义的。

/**
 * @covers \MyClass
 */
class MyClassTest extends TestCase
{
    private $subject;

    private $authorizator;

    /**
     * @testWith ["superPrivilege",false,true]
     *           ["standardPrivilege",true,false]
     *           ["invalidPrivilege",false]
     */
    public function testCanUserdoSomething($privelege,$resourceProperty,$expected)
    {
        $identity = new Identity();
        $resource = new Foo($resourceProperty);
        $this->authorizator->addPrivilege($identity,$resource,$privelege);

        $result = $this->subject->canUserdoSomething($resource,$identity);

        self::assertEquals($expected,$result);
    }

    protected function setUp(): void
    {
        parent::setUp();

        $this->authorizator = new class implements Authorizator {
            private $privileges = [];

            public function addPrivilege(Identity $identity,Foo $resource,string $privilege): void
            {
                $this->privileges[] = spl_object_id($identity) . spl_object_id($resource) . $privilege;
            }

            public function isAllowed(Identity $identity,string $privilege): bool
            {
                return in_array(spl_object_id($identity) . spl_object_id($resource) . $privilege,$this->privileges);
            }
        };

        $this->subject = new MyClass($this->authorizator);
    }
}