在模拟命名空间和原始命名空间中创建模拟 phpunit 差异

creating mock phpunit discrepency in mocked namespace and the original one

我有这样的功能:

class Bar{
    public function a():Foo{
    .
    .
    .
    }
}

现在我正在尝试使用 php 单元测试

为 class 栏创建一个模拟
    $mockedBar = $this->getMockBuilder(Bar::class)
     ->getMock()
     ->method('a')
     ->willReturn(new FakeFoo());

但是当我调用方法 a 时出现错误,方法 a return 类型必须是 Foo 的实例而不是 Mocked_blahblah.

不幸的是class Bar 不使用任何接口,系统非常大,我无法创建接口,因为它在我的代码中进行了大量重构; 有什么方法可以在模拟对象中禁用 return 类型的函数 a 吗? 我正在使用 php7.2 和 phpunit 6.0.13。 这是一个真实的场景:

class A
{
    public function b():B
    {
        echo "i am from class A function b";
    }
}
class B
{

}

class FakeB
{
}
class ATest extends TestCase
{
    public function testSayHi(){
        $mockedA = $this->getMockBuilder(A::class)
            ->getMock();
        $mockedA->method('b')->willReturn(new FakeB());
        $mockedA->b();
    }
}

您无法禁用 return 类型。也许您可以尝试使用某种 hackish 错误处理程序来完成它,但这样做是一件疯狂的事情。

好消息是您没有尝试做任何不寻常的事情,您的测试可以修复。

首先,您需要将getMock的结果赋值给一个变量。接下来,您可以定义测试替身:

class MyTest extends TestCase
{
    public function testIt()
    {
        $mockedBar = $this->getMockBuilder(Bar::class)->getMock();
        $mockedBar
             ->method('a')
             ->willReturn(new FakeFoo());

        $this->assertInstanceOf(Foo::class, $mockedBar->a());
    }
}

这仅在 FakeFoo 的类型为 Foo 时有效,例如扩展它:

class FakeFoo extends Foo
{
    // override any Foo methods you'd like to fake
}

您不需要自己创建一个 Fake,您可以使用 PHPUnit 创建一个虚拟对象:

class MyTest extends TestCase
{
    public function testIt()
    {
        $mockedBar = $this->createMock(Bar::class);
        $mockedBar
             ->method('a')
             ->willReturn($this->createMock(Foo::class));

        $this->assertInstanceOf(Foo::class, $mockedBar->a());
    }
}

修正你的第二个例子:

class A
{
    public function b():B
    {
        echo "i am from class A function b";
    }
}

class B
{
}

class FakeB extends B
{
}

class ATest extends TestCase
{
    public function testSayHi(){
        $mockedA = $this->getMockBuilder(A::class)->getMock();
        $mockedA->method('b')->willReturn(new FakeB());
        $mockedA->b();
    }
}

或者,不使用伪造的让 phpunit 处理它:

class ATest extends TestCase
{
    public function testSayHi(){
        $mockedA = $this->getMockBuilder(A::class)->getMock();
        $dummyB = $this->createMock(B::class);

        $mockedA->method('b')->willReturn($dummyB);
        $mockedA->b();
    }
}