Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit assertEquals strict type check

My objective is to ensure that an object graph has expected values and types. I want to ensure every value is of the expected type.

To this end, assertEquals() is unfortunately not useful:

$this->assertEquals(
    [ 'prop' => '0' ],
    [ 'prop' => 0 ]
);
// -> no failures

In this case, assertSame() works nicely:

$this->assertSame(
    [ 'prop' => '0' ],
    [ 'prop' => 0 ]
);
// Failed asserting that Array &0 (
//     'prop' => 0
// ) is identical to Array &0 (
//     'prop' => '0'
// ).

The problem with assertSame() is that it also checks reference for objects:

$this->assertSame(
    (object) [ 'prop' => 0 ],
    (object) [ 'prop' => 0 ]
);
// Failed asserting that two variables reference the same object.

What options do I have?


On a separate note, I'm not sure why this was designed in this way - to me it feels that assertSame() does two things at once (I've have at most verified object class, not references).

like image 726
Christian Avatar asked Nov 09 '22 10:11

Christian


1 Answers

So far, I came up with the following option:

/**
 * @param mixed $expected
 * @param mixed $actual
 * @param string $message
 */
public function assertObjectGraph($expected, $actual, $message = '')
{
    $expected = $this->convertObjectsToHashes($expected);
    $actual = $this->convertObjectsToHashes($actual);

    $this->assertSame($expected, $actual, $message);
}

/**
 * @param mixed $value
 * @return mixed
 */
private function convertObjectsToHashes($value)
{
    if (is_object($value)) {
        $value = ['__CLASS__' => get_class($value)] + get_object_vars($value);
    }

    if (is_array($value)) {
        $value = array_map([$this, __FUNCTION__], $value);
    }

    return $value;
}

Examples:

$this->assertObjectGraph(
    (object) [ 'prop' => 0 ],
    (object) [ 'prop' => 0 ]
);
// -> ok

$this->assertObjectGraph(
    (object) [ 'prop' => 0 ],
    (object) [ 'prop' => '0' ],
);
// Failed asserting that Array &0 (
//     '__CLASS__' => 'stdClass'
//     'prop' => '0'
// ) is identical to Array &0 (
//     '__CLASS__' => 'stdClass'
//     'prop' => 0
// ).

class Test{public $prop = 0;}
$this->assertObjectGraph(
    (object) [ 'prop' => 0 ],
    new Test()
);
// Failed asserting that Array &0 (
//     '__CLASS__' => 'Test'
//     'prop' => 0
// ) is identical to Array &0 (
//     '__CLASS__' => 'stdClass'
//     'prop' => 0
// ).
like image 108
Christian Avatar answered Jan 04 '23 02:01

Christian