Laravel
February 21

Бесполезное сообщение об ошибке при использовании BackedEnum и assertJson

Возможно, вам интересно, почему...

Вот интересный сценарий, с которым недавно столкнулся.

Допустим, необходимо протестировать ответ API, и его значение включает `BackedEnum`:

// app/Enums/Urgency.php
enum Urgency: string {
    case LOW = 'low';
    case MEDIUM = 'medium';
    case HIGH = 'high';
}

// tests/Feature/ExampleTest.php
$response->assertJson([
    'data' => [
        'urgency' => Urgency::LOW,
    ],
])

Этот тест завершится неудачей, потому что перечисление не соответствует строковому значению в JSON-ответе. Это легко исправить, просто добавьте `->value` к перечислению, и тест будет пройден. Ничего страшного!

Но вот тут-то и становится интересно. Посмотрите внимательно на сообщение об ошибке при неудачном завершении теста:

Unable to find JSON: 

[{
    "data": {
        "urgency": "low"
    }
}]

within response JSON:

[{
    "data": {
        "urgency": "low"
    }
}]

Оба значения совпадают! Этот пример предельно прост, поэтому странности легче заметить, но теперь представьте это в ответе с десятками ключей и значений.

Что происходит?

Внутри метода теста Laravel `assertJson` он откладывает утверждение для `PHPUnit::assertArraySubset`. Как и ожидалось, метод PHPUnit воспринимает объект `BackedEnum` и строковое значение как разные, поэтому тест проваливается, как и должно быть.

Но когда Laravel вызывает это утверждение PHPUnit, он также передает сообщение об ошибке, чтобы показать, если утверждение завершилось неудачно. И чтобы сделать сообщение об ошибке более красиво оформленным, он форматирует ожидаемые и фактические значения с помощью `json_encode` с красивым выводом.

Когда вы `json_encode` объект `BackedEnum`, он вернет строковое значение перечисления, а не сам объект перечисления.

Таким образом, тест проваливается, но сообщение об ошибке выглядит так, как будто он должен быть пройден.