phparrayssymfonypass-by-referenceprophecy

Add value to array in Symfony TestCase class in test function if the array was initialised in setUp method


Apologies if the question looks off, I am new to both Stack Overflow and php.

My class looks a bit like this:

final class MyClass extends TestCase
{
  private MyService $myService;
  private ObjectProphecy $object;
  private array $x;

  protected function setUp(): void
  {
    $this->object = $this->getProphet()->prophesize(MyOtherClass::class);

    $this->x = [];
    $this->object->foo()->willReturn($this->x);
  }

  public function test(): void
  {
    $this->x = [1];
    $this->myService->bar();
  }
}

The issue is that within the call of $this->myService->bar();, on the execution of object->foo(), I get [], which was set in the setUp() method, and I'd like it to be [1] instead.

I suspect this is because $this->object->foo()->willReturn($this->x); makes a copy of $this->x and then doesn't notice the change I make later on. However, if I change $x to be some object instead of array, everything works as I'd expect it to work.

What would be the cleanest way of dealing with this? I was hoping for something like declaring $x to be pointer to array but that doesn't seem to be possible?


Solution

  • There is the possibility to return a reference. Tested for PHPUnit 10.3.

    Note

    This was not tested with ObjectProphecy which does not seem to implement the default mocking object. So for this example code I've used the native PHPUnit MockObject instead.

    <?php declare(strict_types=1);
    
    use PHPUnit\Framework\MockObject\MockObject;
    use PHPUnit\Framework\TestCase;
    
    // Never used, but neccessary to have a class to be able to create a mock
    class MyFoo {
        public function foo(): array
        {
            var_dump('called foo()');
    
            return ['foo'];
        }
    }
    
    final class ReturnTest extends TestCase
    {
        private MockObject $mock;
        private array      $x;
    
        protected function setUp(): void
        {
            $this->x = [];
            $this->mock = $this->createMock(MyFoo::class);
            $this->mock->method('foo')->willReturnReference($this->x);
        }
    
        public function test(): void
        {
            $this->assertEquals([], $this->mock->foo());
            $this->x = [1];
            $this->assertEquals([1], $this->mock->foo());
        }
    }