AssertEquals 和 assert势均力敌在 PHPUnit 中是否相同?

PHPUnit 包含一个 assertEquals()方法,但它也有一个 assertSame()方法。乍一看,它们似乎做着同样的事情。

这两者之间的区别是什么? 为什么它们都被指定?

84525 次浏览

我偶尔都会用,但根据文件记录:

assertSame

如果两个变量 $expected$actual类型价值不相同,则报告一个由 $message识别的错误

正如你在上面的例子中看到的,他们通过了 '2204'2204,使用 assertSame会失败,因为一个是 string,一个基本上是 int,:

'2204' !== 2204
assertSame('2204', 2204) // this test fails

assertEquals

“报告一个错误,该错误由 $message 标识,如果两个变量 $ 预期值和 $实际值不相等。”

assertEquals似乎没有考虑到数据类型,因此使用上面的 2204例子:

'2204' == 2204
assertEquals('2204', 2204) // this test passes

我只是针对上面的例子运行了一些单元测试,实际上它们导致了文档化的行为。

$this->assertEquals(3, true);
$this->assertSame(3, true);

第一个会通过的!

第二个会失败。

这就是区别。

我认为你应该一如既往地使用 assert。

assertSame () = = 测试实际输出和预期参数是否相同。

即:

$this->assertSame('$expected','$expected');

或者

$this->assertSame('100','100');

AssertEquals = = 如果我们看到一个网站页面,我有一个有2个“ table”的页面,所以当我运行 assertEquals 时,我会使用 count 函数检查它的 count,“ table”是2。 例如:

$this->assertEquals(2, $var->filter('table')->count());

在这里,我们可以看到 assertEquals 检查 Web 页面上是否有2个表。我们也可以在括号中使用“ # Division name”来使用页面上的除法。

例子2:

public function testAdd()
{
$calc = new Calculator();


$result = $calc->add(30, 12);


// assert that our calculator added the numbers correctly!
$this->assertEquals(42, $result);
}

而且,

// Passes
$this->assertSame("123.", "123.");
$this->assertEquals("123.", "123");
// Fails
$this->assertSame("123.", "123");

当涉及到物体比较时:

一样

只能在两个对象引用同一个对象实例时断言。因此,即使两个单独的对象的所有属性的值完全相同,如果它们不引用相同的实例,assertSame()也会失败。

$expected = new \stdClass();
$expected->foo = 'foo';
$expected->bar = 'bar';


$actual = new \stdClass();
$actual->foo = 'foo';
$actual->bar = 'bar';


$this->assertSame($expected, $actual); // FAILS

AssertEquals

如果两个单独的对象在任何情况下都匹配其属性值,则可以断言。因此它是适合于断言对象匹配的方法。

$this->assertEquals($expected, $actual); // PASSES

参考文献

如前所述,如果两个元素不共享 类型价值assertSame会报告一个错误,但是从 文件中注意到这一点也很重要:

如果两个变量 $expected,则报告一个由 $message标识的错误 和 $actual不引用同一个对象。

因此,即使它们共享类型和值,这个测试也会失败:

class SameTest extends TestCase
{
public function testFailure()
{
$this->assertSame(new stdClass, new stdClass);
}
}

正如前面提到的,assertEquals()主要是关于一个解释值,不管是通过类型杂耍还是使用 _ _ magic 表示方法的对象(例如 __toString())。

assertSame()的一个很好的用例是测试一个单例工厂。

class CacheFactoryTest extends TestCase
{
public function testThatCacheFactoryReturnsSingletons()
{
$this->assertSame(CacheFactory::create(), CacheFactory::create());
}
}

永远不要使用 assertEquals(和家庭) *

* 除非参数首先被手动类型检查,或者你完全了解这种行为,并且准备好测试通过,当它对待,比如说,true42相等时——我无法想象为什么一个人会容忍在关键测试代码中极其微妙的假阳性的风险。

用于基元值(浮点数除外)和数组

使用 assertSame。行为是可预测的。 "42"true不相等。

为了花车

尽可能避免使用整数。如果你必须比较浮点数,assertEqualsWithDeltaassertEquals一样破碎:

$this->assertEqualsWithDelta(0.99, "1", 0.1); // passes :\
$this->assertEqualsWithDelta(99999, true, 0.1); // passes D:

assertEqualsWithDelta的实现使用了一种不准确的方法,正如 比较浮点数所描述的: abs($this->value - $other) < PHP_FLOAT_EPSILON;,因此您可能需要编写一个自定义函数。

或者在调用 assertEqualsWithDelta之前进行类型检查,以避免更紧迫的问题:

function is_number($v) {
return is_float($v) || is_int($v);
}


class FloatTest extends TestCase {
private function assertClose(
$expected,
$actual,
$delta = 1e-7
): void {
if (!is_number($expected)) {
$type = gettype($expected);
throw new Error("\$expected type $type was not a number");
}
else if (!is_number($actual)) {
$type = gettype($actual);
throw new Error("\$actual value $type was not a number");
}
else if (!is_number($delta)) {
$type = gettype($delta);
throw new Error("\$delta value $type was not a number");
}
    

$this->assertEqualsWithDelta($actual, $expected, $delta);
}


public function testFloats() {
$this->assertClose(2, "2"); // fails as it should
}
}

物品

使用定制的 equals(self $other): bool函数和 assertObjectEquals

如果一切都失败了

使用 assertTrue是不会出错的,缺点是缺乏语义适当性和缺省错误消息。