PHPUnit assertEquals严格的类型检查

PHPUnit assertEquals严格的类型检查,phpunit,assertions,Phpunit,Assertions,我的目标是确保对象图具有预期的值和类型。我想确保每个值都是预期的类型 为此,assertEquals()不幸没有什么用处: $this->assertEquals( [ 'prop' => '0' ], [ 'prop' => 0 ] ); // -> no failures 在这种情况下,assertSame()可以很好地工作: $this->assertSame( [ 'prop' => '0' ], [ 'prop' =

我的目标是确保对象图具有预期的值和类型。我想确保每个值都是预期的类型

为此,
assertEquals()
不幸没有什么用处:

$this->assertEquals(
    [ 'prop' => '0' ],
    [ 'prop' => 0 ]
);
// -> no failures
在这种情况下,
assertSame()
可以很好地工作:

$this->assertSame(
    [ 'prop' => '0' ],
    [ 'prop' => 0 ]
);
// Failed asserting that Array &0 (
//     'prop' => 0
// ) is identical to Array &0 (
//     'prop' => '0'
// ).
assertSame()
的问题在于它还检查对象的引用:

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



另一方面,我不知道为什么会这样设计-对我来说,
assertSame()
可以同时做两件事(我最多有验证过的对象类,而不是引用)。

您可以先检查数组键是否存在,然后检查正确的类型,例如:

    $this->assertArrayHasKey('prop', $input);
    $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_INT, $input['prop']);
    // or more simply as this->assertTrue(is_int($new_id));
    $this->assertEquals(0, $input['prop']);

希望对您有所帮助

到目前为止,我提出了以下选项:

/**
 * @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;
}
示例:

$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
// ).

由于您的目标似乎是比较两个阵列,
应该注意的是,在官方的PHP手册中-,描述了对数组的
==
操作符的支持

如果$a和$b中有相同的键/值对,则$a===$b标识为TRUE 相同的顺序和相同类型的相同类型仅适用于值-不检查键类型

所以,您要做的是在一个真正的断言中比较这个结果:

$this->assertTrue(['a' => '1', 'b' => '2'] === ['a' => 1, 'b' => '2']);
assertEquals()
在您的案例中失败,因为它完全按照它所说的做,它使用
=
-一个
equal
操作符进行测试,我承认它不是真正直观的,并且带来了一些时髦的东西,比如

$this->assertEquals(321, true); // this would PASS!

对于对象,您应该定义一个完整的单独比较器。

检查一个属性很容易,但对整个对象图来说就不那么容易了。。当然,您好。但通过这种方式,您可以直接指向问题(字段的类型而不是值),而不是一个不同于另一个的大对象图。
assertSame()
用于检查“两个变量是否引用同一个对象”-而不是它们是否相同,但是,不管它是否是相同的引用,这里您显式地创建了两个对象,每个对象都有内部不同的引用。@java.web
assertSame()
处理对象的方式与其他类型不同,因为它模仿PHP的
=
assertSame
用于检查类型(这是
1==='1'
为false的目的),但对象除外,其中需要精确的对象。我在这里问的是基本一致的行为,因为我对对象引用是否相同不感兴趣,而是对对象类型和内容是否相同感兴趣。这里没有“java”……无论如何,我只是指出了为什么这种方法不起作用。我很惊讶2020年仍然没有一个理想的解决方案。尽管下面提供的解决方案确实解决了这个问题,但在断言对象的属性都具有相同的值方面,它们都不是理想的解决方案。我想知道这是否有历史原因。我很惊讶在2020年phpunit仍然没有一个本地解决方案。类似于$this->assertedentical()的东西将是理想的选择。尽管下面提供的解决方案确实解决了这个问题,但在断言对象的属性都具有相同的值(出于各种原因)方面,它们都不是理想的解决方案。我想知道这是否有历史原因。
$this->assertTrue(['a'=>'1','b'=>'2']====['a'=>1',b'=>'2'])。。。是的,当一个非常复杂的对象/数组失败时,你会得到什么?“预期失败,预期为true,但发现为false”很抱歉,您的Q示例和A代码以比较2个数组结束-因此我不太清楚其意图。不过,我同意显示比较项的转储可能会很方便,尽管这不是必需的,而且您基本上已经编写了自己的比较器-我想这是显而易见的,您应该了解如何将对象转换为数组。很酷,但我担心的是,您会收到整个对象的一条错误消息。如果对象中有一个属性(如示例中所示),则错误消息是可读的。但是,如果您有数百个属性,那么每次测试失败时,解析一条长错误消息以查找对象中的一个或两个差异将是额外的工作。