PHPUnit:对多个接口进行存根

Gor*_*onM 7 php phpunit interface stub

我已经掌握了PHPUnit,并且到目前为止发现它很容易使用,但是我遇到了一个导致我遇到困难的测试用例.

我正在编写针对一组接口的代码,这些接口需要实现对象(一些PHP,一些是自制的),而SUT需要一个输入对象来实现多个接口.例如:

class MyClass implements ArrayAccess, MyInterface
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

SUT做的事情如下:

class ClassToBeTested
{
    protected $obj = NULL;

    public function __construct ($obj)
    {
        $this -> obj = $obj;
    }

    public function methodToBeTested ()
    {
        if ($this -> obj instanceof ArrayAccess)
        && ($this -> obj instanceof MyInterface)
        {
            // ...
        }
    }

    public function otherMethodUnderTest ()
    {
        if ($this -> obj instanceof ArrayAccess)
        {
            // ...
        }
        else
        if ($this -> obj instanceof MyInterface)
        {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以从一个接口或另一个接口创建存根,但我不知道你是否可以创建一个实现它们的存根.

protected function setUp ()
{
    $stubField  = $this -> getMockBuilder ('ArrayAccess')
            -> getMock ();
    $this -> object = new ClassToBeTested ($stubField);
}
Run Code Online (Sandbox Code Playgroud)

要么

protected function setUp ()
{
    $stubField  = $this -> getMockBuilder ('MyInterface')
            -> getMock ();
    $this -> object = new ClassToBeTested ($stubField);
}
Run Code Online (Sandbox Code Playgroud)

是否可以从接口列表生成存根,或者我是否必须存根实现预期接口的具体类?这本身就造成了困难,因为需要存根的类本身需要将另一个对象传递给它的构造函数,而我似乎无法使disableOriginalConstructor()或setConstructorArgs()工作我认为这是因为有问题的具体类本身并不实现构造函数,而是从超类继承它.我错过了一些明显的东西吗?

liq*_*car 6

您是否有权编辑原始代码?如果是这样,我将创建一个扩展ArrayAccess和MyInterface的新接口.这样你就可以存根/模拟一个对象来测试被测方法.


小智 5

对于将来,如果有人碰巧看到此答案,则在PHPUnit 7中对我有用:

$mock = $this
  ->getMockBuilder([InterfaceA::class,InterfaceB::class])
  ->getMock();
Run Code Online (Sandbox Code Playgroud)

  • 从 PHPUnit 8.5 开始,这不再可能:https://github.com/sebastianbergmann/phpunit/issues/3955 (5认同)
  • 你也可以做`$this->createMock([A::class, B::class])` (2认同)

Oli*_*ier 5

PHPUnit 10(2023 年 2 月)引入了createMockForIntersectionOfInterfaces() 和方法(在348ffd6d#5122等中),重新引入了 API 来创建实现多个接口的模拟。createStubForIntersectionOfInterfaces() TestCase

之前此功能在 PHPUnit 9 之前可用(不包括,在ab5b024a中删除;自 8.5 #3955起已弃用)

取自文档的示例:

interface X
{
    public function m(): bool;
}
Run Code Online (Sandbox Code Playgroud)
interface Y
{
    public function n(): int;
}
Run Code Online (Sandbox Code Playgroud)
class Z
{
    public function doSomething(X&Y $input): bool
    {
        $result = false;

        // ...

        return $result;
    }
}
Run Code Online (Sandbox Code Playgroud)
use PHPUnit\Framework\TestCase;

class MockForIntersectionExampleTest extends TestCase
{
    public function testCreateMockForIntersection(): void
    {
        $o = $this->createMockForIntersectionOfInterfaces([X::class, Y::class]);

        // $o is of type X ...
        $this->assertInstanceOf(X::class, $o);

        // ... and $o is of type Y
        $this->assertInstanceOf(Y::class, $o);
    }
}
Run Code Online (Sandbox Code Playgroud)