Phpunit,如何模拟抽象类?

Phpunit,如何模拟抽象类?,php,unit-testing,mocking,phpunit,Php,Unit Testing,Mocking,Phpunit,我说的是这个功能: function testMeSomehow ($id, Flag $flags) { $flags::NAME; } 其参数对象: abstract class Flag { abstract function method1(); abstract function method2(); . . . abstract function method999(); } 如何模拟这个标志类?它有很多抽象的方法,我应该用空的主体来创建它们吗?如

我说的是这个功能:

function testMeSomehow ($id, Flag $flags)
{
    $flags::NAME;
}
其参数对象:

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

如何模拟这个
标志
类?它有很多抽象的方法,我应该用空的主体来创建它们吗?如果这个类发生变化呢?我还必须向它添加一个
名称
常量

您可以像对任何其他类一样,使用测试加倍来模拟它,请参见

这可能是一个示例测试:

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));
    }
}
您可以将要由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()
方法,因此我个人更喜欢前面的建议:模拟具有更改值的子类。

如果您先尝试怎么办?为什么您认为模拟抽象类不同于模拟普通类或接口?没错,但是看到$flags::NAME了吗?如何为模拟设置常量?我添加了一个访问常量的示例,这段代码适合我。不可能动态更改常量值。如果您真的想为不同的测试指定许多不同的值,我添加了一个变通方法,但是我会使用前面的解决方案。