如您所知,在 PHPUnit 中,我们使用
assertEquals()
和 assertSame()
并将数组传递给它们,它们将根据键值对断言数组。因此,如果数组是非关联数组(列表)并且顺序无关紧要,则测试将失败,因为这些方法将索引视为键并比较每个相应键的值。
这个问题可以通过自定义断言方法轻松解决,如下所示:
protected function assertListWithoutOrderEquals(array $expected, array $actual): void
{
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
}
但是当我们在 Laravel HTTP 测试中并且我们有 JSON 来断言时,我认为 Laravel 会将 JSON 转换为数组并根据这些方法断言它们。我不知道如何解决这个问题。
例如,我在 Laravel 中进行了此测试,并且在断言
genres
值时遇到问题。:
use Illuminate\Testing\Fluent\AssertableJson;
public function test_http_response(): void
{
$expectedData = [
'id' => 1,
'name' => 'The fantastic book',
'genres' => ['science-fiction', 'drama', 'mystery'],
// other elements
];
$response = $this->get('url');
$response->assertJson(
fn(AssertableJson $json) => $json->where('id', $expectedData['id'])
->where('name', $expectedData['name'])
->where('genres', $expectedData['genres']) // This is order sensitive and makes tests to fail.
->etc()
);
}
我尝试过这个,但很混乱。如果您能帮助我,我正在寻找更好、更清洁的解决方案。
->where('genres', fn($genres) => $genres->diff($expectedData['genres'])->isEmpty() && $genres->count() == count($expectedData['genres']))
为了更好地解释,Laravel 会将 JSON 数组转换为集合,所以我检查了
diff()
并且由于 diff() 是一种单向方法,我的意思是它检查第一个数组中的所有项目是否存在于第二个数组中,并且不要考虑第二个数组中的额外项目,我也检查了它们的大小。
我认为在这种情况下回调是必要的,但您可以利用 PHPUnit 用于实现的相同逻辑 assertEqualsCanonicalizing
$expectedData = [
'id' => 1,
'name' => 'The fantastic book',
'genres' => ['science-fiction', 'drama', 'mystery'],
// other elements
];
$result = $this->get('url');
$result->assertJson(
fn(AssertableJson $json) => $json->where('id', $expectedData['id'])
->where('name', $expectedData['name'])
->where('genres', fn ($val) => (new IsEqualCanonicalizing($val->all()))->evaluate($expectedData['genres']))
);
我不确定这是否是“最好”的方式,但它是“一种”方式。