如何对PHP traits进行单元测试

67

我想知道如何对一个PHP trait进行单元测试的解决方案。

我知道我们可以测试使用该trait的类,但我想知道是否有更好的方法。

提前感谢任何建议 :)

编辑

一种替代方案是在测试类中使用该Trait,就像我下面要演示的那样。

但是我并不喜欢这种方法,因为不能保证Trait、类和PHPUnit_Framework_TestCase(在此示例中)之间没有相似的方法名:

这里是一个示例Trait:

trait IndexableTrait
{
    /** @var int */
    private $index;

    /**
     * @param $index
     * @return $this
     * @throw \InvalidArgumentException
     */
    public function setIndex($index)
    {
        if (false === filter_var($index, FILTER_VALIDATE_INT)) {
            throw new \InvalidArgumentException('$index must be integer.');
        }

        $this->index = $index;

        return $this;
    }

    /**
     * @return int|null
     */
    public function getIndex()
    {
        return $this->index;
    }
}

以及它的测试:

class TheAboveTraitTest extends \PHPUnit_Framework_TestCase
{
    use TheAboveTrait;

    public function test_indexSetterAndGetter()
    {
        $this->setIndex(123);
        $this->assertEquals(123, $this->getIndex());
    }

    public function test_indexIntValidation()
    {
        $this->setExpectedException(\Exception::class, '$index must be integer.');
        $this->setIndex('bad index');
    }
}

请提供您尝试过但未能成功的代码。这将有助于其他人协助您。 - Adam B
@AdamB,我自己写了第一个答案,其中包含示例代码。但是请注意,这并不意味着有什么故障或不正常的情况,我只是想知道是否有任何好的方法可以直接对traits进行单元测试,而不是通过单元测试使用该trait的类间接测试它们。谢谢。 - Ali
3个回答

109

您可以使用与测试抽象类的具体方法类似的方式测试Trait。

PHPUnit有一个名为getMockForTrait的方法,它将返回使用Trait的对象。然后,您可以测试Trait的函数。

这是文档中的示例:

<?php
trait AbstractTrait
{
    public function concreteMethod()
    {
        return $this->abstractMethod();
    }

    public abstract function abstractMethod();
}

class TraitClassTest extends PHPUnit_Framework_TestCase
{
    public function testConcreteMethod()
    {
        $mock = $this->getMockForTrait('AbstractTrait');

        $mock->expects($this->any())
             ->method('abstractMethod')
             ->will($this->returnValue(TRUE));

        $this->assertTrue($mock->concreteMethod());
    }
}
?>

15

自从PHP 7以来,现在我们可以使用匿名类...

$class = new class {
    use TheTraitToTest;
};

// We now have everything available to test using $class

11

如果需要的话,您也可以使用getObjectForTrait,然后断言实际结果。

class YourTraitTest extends TestCase
{
    public function testGetQueueConfigFactoryWillCreateConfig()
    {
        $obj = $this->getObjectForTrait(YourTrait::class);

        $config = $obj->getQueueConfigFactory();

        $this->assertInstanceOf(QueueConfigFactory::class, $config);
    }

    public function testGetQueueServiceWithoutInstanceWillCreateConfig()
    {
        $obj = $this->getObjectForTrait(YourTrait::class);

        $service = $obj->getQueueService();

        $this->assertInstanceOf(QueueService::class, $service);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接