Laravel / PHPUnit:断言两个模型的相同

11

在Laravel中进行数据库集成测试时,如何断言两个相同的Eloquent模型实例是相同的?

AssertEquals $model $model

简单使用 ->assertEquals($modelOne, $modelTwo); 是不行的,因为即使它们相同的,PHPUnit也会检查类属性,例如wasRecentlyCreated ,有时模型的id可以是字符串或整数。

AssertEquals $model->id $model->id

这里的问题是,模型一可能是另一个模型的实例,例如:

AssertEquals(Person::find(1)->id, Animal::find(1)->id); 返回true。

AssertEquals $model->toArray() $model->toArray()

这里的问题是属性并不总是以相同类型转换,我不是100%确定原因,但有时模型的属性将是int,而其他时候则是数值string

AssertEquals($address->toArray(), $user->address->toArray())

[ postcode => 2454 ]
[ postcode => "2454" ]
如何以简单、干净且可重复的方式断言两个 Eloquent 模型是同一个数据库记录?

你是否只想比较从数据库中获取的最新模型? - Jonas Staudenmeir
你能补充一下具体想要测试的内容吗?你是在测试像 Model::create() 这样的东西是否正确地持久化,还是其他什么呢? - Aken Roberts
1个回答

35

一个选择是使用PHPUnit的assertTrue方法,结合Illuminate\Database\Eloquent类上的is方法。

$this->assertTrue($modelOne->is($modelTwo));

is 方法将会返回 true ,如果你传入的模型不是 null,并且具有相同的主键、相同的表和相同的连接。

当涉及到测试属性是否相同时,你可以安全地仅使用 PHPUnit 的 assertEquals 来比较每个模型的属性,这些属性可以通过 getAttributes 方法获取。

$model1 = new Model(['id' => 1, 'name' => 'test', 'enabled' => 0, 'number' => '1']);
$model2 = new Model(['id' => 1, 'name' => 'test', 'enabled' => false, 'number' => 1]);

$this->assertEquals($model1->getAttributes(), $model2->getAttributes());

在我的测试中,我发现这些断言都是正确的。 assertEquals 方法会宽松地比较值, 即使用 == 而非严格比较(或身份)运算符 === 。在内部,它将对提供的两个数组进行排序,并宽松地比较具有相同键的值。如果一个模型上有额外的属性而另一个模型没有,则断言也将失败。


哇,太棒了,正是我所期望的。虽然在保存记录之前,属性可能不同,但缺少“相似性”。 - AndrewMcLagan
有人编写了一些断言,比如 assertModelEquals(Model $expected, Model $actual)assertModelSameness(Model $expected, Model $actual) 吗? - AndrewMcLagan
我认为你可以放心地在每个模型的属性上使用assertEquals。请查看我的更新答案。 - Jonathon
toArray和getAttributes有什么区别? - AndrewMcLagan
1
getAttributes 只是返回表示模型属性的内部数组。 toArray 做了更多的事情,它调用 mutators,包括关系,转换属性(由 $casts 属性定义),省略隐藏的属性(由 $hidden 属性定义)等等。 getAttributes 更简单,它不进行任何额外的处理,只返回模型所代表的基础数据。 - Jonathon
请注意,如果您想更加严格,可以使用 assertSame 而不是 assertEquals,这相当于使用 === 而不是 ==。每个都有自己的用途。 - Jeremy Belolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接