Symfony ObjectProphecy 以不同方式对待数组和对象 - 无法更改在 setUp 方法中初始化的数组

问题描述 投票:0回答:1

相关

我正在尝试这个测试代码

<?php

use Monolog\Test\TestCase;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophet;

class MyBar {
    public int $bar = 0;
}

class MyFoo {
    public function fooArray(): array {
        return [];
    }

    public function fooBar(): MyBar {
        return new MyBar();
    }

    public function fooInt(): int {
        return 0;
    }
}

final class SimpleTest extends TestCase
{
    private Prophet $prophet;
    private ObjectProphecy $mock;
    private array $myArray;
    private MyBar $myBar;
    private int $myInt;

    public function getProphet(): Prophet {
        return $this->prophet;
    }

    protected function setUp(): void {
        $this->prophet = new Prophet();
        $this->myArray = [0];
        $this->myBar = new MyBar();
        $this->myInt = 0;
        $this->mock = $this->getProphet()->prophesize(MyFoo::class);
        $this->mock->fooArray()->willReturn($this->myArray);
        $this->mock->fooBar()->willReturn($this->myBar);
        $this->mock->fooInt()->willReturn($this->myInt);
    }
    
    public function test(): void {
        $this->myArray = [1];
        $this->assertEquals([0], $this->mock->reveal()->fooArray());

        $this->myBar->bar = 1;
        $this->assertEquals(1, $this->mock->reveal()->fooBar()->bar);

        $this->myInt = 1;
        $this->assertEquals(0, $this->mock->reveal()->fooInt());
    }
}


请注意测试函数中的差异,数组

$myArray
不会更新,int
$myInt
也不会更新,但对象
$myBar
会更新。

  • 为什么他们不以同样的方式行事?
  • 让数组像对象一样工作的推荐方法是什么?

我正在考虑将数组作为参考传递,但根据this

ObjectProphecy
可能无法实现。我在顶部链接的问题的答案建议使用另一种方法
MockObject
来解决,但我试图看看
ObjectProphecy
中是否有解决方案。

arrays symfony pass-by-reference prophecy
1个回答
0
投票

您正在测试完全不同的东西(比较番茄和土豆)。希望我在下面已经很好地解释了这种情况。

回答你的第一个问题,我以

$this->myInt
为例(不过,这也涉及到
$this->myArray
);

在您的

setup()
函数中,您使用三个步骤:

  1. 您的第一步是将

    0
    分配给
    $this->myInt

    $this->myInt = 0;

  2. 你的第二步是创建一个对象:

    $this->mock = $this->getProphet()->prophesize(MyFoo::class);

  3. 你的第三步(#3)是为对象分配值

    0
    (来自
    $this->myInt
    ):

    $this->mock->fooInt()->willReturn($this->myInt);

然后在你的实际测试函数中(

test()
):

  1. 作为第四步 (#4),您将

    $this->myInt
    值更改为
    1

    $this->myInt = 1;

  2. 作为第五步(#5),您实际上正在测试

    object
    的值,根据
    step #3
    仍应返回
    0

    $this->assertEquals(0, $this->mock->reveal()->fooInt());

在最后一步中,您实际上是将

0
与您在
step #3
中设置的值(根据
$this->myInt = 0
step #1
)进行比较。例如。您的测试将通过
Step #4
没有做任何事情,因为您没有更改对象的值(您正在测试),您只是更改
class
中的私有参数的值。仅当您测试
$this->myInt
的值时,您的预期行为才有效,如下所示:

$this->assertEquals(0, $this->myInt);

因此,要解决您的问题,请重写您的测试或确保您更改正确的值(在您的

class
内或在
object
内)。

为了解释您的

object
示例以及为什么有所不同,您实际上是在更改
object
中的值并在测试中测试相同的
value
(正确测试):

$this->myBar->bar = 1;
$this->assertEquals(1, $this->mock->reveal()->fooBar()->bar);

您更改了

value
中的
object
。再一次,您的测试将通过

要回答你的第二个问题,请将

step #4
更改为:

$this->myInt = 1;
$this->mock->fooInt()->willReturn($this->myInt);
// and then to do your test from step #5:
$this->assertEquals(0, $this->mock->reveal()->fooInt());
// this should fail.
© www.soinside.com 2019 - 2024. All rights reserved.