Related to this
I am trying out this test code
<?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());
}
}
Notice the difference in test function how array $myArray doesn't get updated, nor does int $myInt, but object $myBar does.
- Why do they not act in the same way?
- What would be the recommended way of having the array act like the object does?
I was thinking about passing the array as a reference, but according to this, it might not be possible with ObjectProphecy. The answer to the question I linked at the top suggests the solution using another approach with MockObject, but I am trying to see whether there is a solution within ObjectProphecy.
You are testing something completely different (comparing tomato with potato). Hopefully I have explained the situation well enough below.
To answer your first question, I used
$this->myIntas an example (however, this also concerns$this->myArray);In your
setup()function you are using three steps:Your first step is assigning
0to$this->myInt:$this->myInt = 0;Your second step is creating an object:
$this->mock = $this->getProphet()->prophesize(MyFoo::class);Your third step (#3) is assigning the object with value
0(from$this->myInt):$this->mock->fooInt()->willReturn($this->myInt);Then in your actual test function (
test()):As a fourth step (#4), you are changing
$this->myIntvalue to1:$this->myInt = 1;As a fifth step (#5) you are actually testing the value of the
objectwhich according tostep #3should still return0:$this->assertEquals(0, $this->mock->reveal()->fooInt());In the last step, you are actually comparing
0with the value you set instep #3(which was$this->myInt = 0accoring tostep #1). E.g. your test will pass.Step #4is not doing anything, since you are not changing the value of your object (which you are testing), you are only changing the value of the private parameter within yourclass. Your expected behaviour only works when you test the value of$this->myInt, so like this:$this->assertEquals(0, $this->myInt);So to solve your problem, either rewrite your test OR make sure that you are changing the correct value (either within your
classor within theobject).To explain your
objectexample and why this is different, you are actually changing the value within yourobjectand testing the samevaluein you test (testing it correctly):You changed the
valuewithin theobject. Once again, your test will pass.To answer your second question, change
step #4into: