Phpunit,如何模拟抽象类?

时间:2015-09-08 20:40:55

标签: php unit-testing mocking phpunit

我在谈论这个功能:

function testMeSomehow ($id, Flag $flags)
{
    $flags::NAME;
}

其参数对象:

abstract class Flag
{
    abstract function method1();
    abstract function method2();
.
.
.
    abstract function method999();
}

如何模拟这个Flag课程?它有大量的抽象方法,我应该用空体创建所有这些方法吗?如果这堂课改变怎么办?我还必须向其添加NAME常量

1 个答案:

答案 0 :(得分:2)

您可以使用测试双打来模拟它,就像您对其他任何课程一样,请参阅https://phpunit.de/manual/current/en/test-doubles.html

这可能是一个示例测试:

class TargetClass
{
    public function testMeSomehow($id, Flag $flag)
    {
        return $flag->method1();
    }
}

class TargetClassTest extends PHPUnit_Framework_TestCase
{
    public function testSomething()
    {
        $mock = $this->getMock('Flag');
        $mock->expects($this->once())
            ->method('method1')
            ->willReturn('methodResult');

        $targetClass = new TargetClass();
        $this->assertEquals('methodResult', $classToTest->testMeSomehow(1, $mock));
    }
}

您可以指定要将模拟替换为$this->getMock()的第二个参数的方法。因为我们根本没有指定任何东西,它将取代所有方法,因此不会对抽象方法感到烦恼。

编辑:添加了一个访问常量的示例:

class ClassToTest
{
    public function testMeSomehow($id, Flag $flag)
    {
        return $flag::NAME;
    }
}

class FlagTest extends PHPUnit_Framework_TestCase
{
    public function testStuff()
    {
        $mock = $this->getMock('Flag');
        $classToTest = new ClassToTest();
        $this->assertEquals('Flag name', $classToTest->testMeSomehow(1, $mock));
    }
}

如果你想在测试中为该常量指定一个特定值,我建议使用这个常量创建一个子类,并将其用于模拟。

编辑:添加了一个示例,其中包含指定动态常量值的变通方法。

class Flag
{
    const NAME = 'Flag name';

    public function getName()
    {
        return static::NAME;
    }
}

class TargetClass
{
    public function testMeSomehow($id, Flag $flag)
    {
        return $flag->getName();
    }
}

class TargetClassTest extends PHPUnit_Framework_TestCase
{
    public function testSomething()
    {
        $mock = $this->getMock('Flag');
        $mock->expects($this->any())
            ->method('getName')
            ->willReturn('New flag name');

        $targetClass = new TargetClass();
        $this->assertEquals('New flag name', $classToTest->testMeSomehow(1, $mock));
    }
}

然而,这迫使你到处使用getName()方法,所以我个人更喜欢以前的建议:模拟一个具有更改值的子类。