Laravel
March 31

Не все тестовые утверждения одинаково обрабатывают перечисления

Убедитесь, что знаете, как они работают

Вчера я поделился сценарием, в котором сбой теста с assertJson возвращал не очень полезную ошибку с перечислением.

Сегодня я хочу продолжить это обсуждение и обратить внимание на то, что не все тестовые утверждения одинаково обрабатывают перечисления.

Например, можно передать экземпляр BackedEnum непосредственно в assertExactJson, и он пройдет:

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

// tests/Feature/ExampleTest.php
$response->assertExactJson([
    'data' => [
        'urgency' => Urgency::LOW, // здесь не требуется ->value
    ],
])

Почему это проходит, в то время как аналогичный подход с assertJson проваливается?

Как уже говорилось ранее, assertJson передает данные в базовое утверждение PHPUnit.

Но в assertExactJson используется объект AssertableJsonString, позволяющий обработать данные перед передачей их в PHPUnit::assertEquals:

// taken from src/Illuminate/Testing/AssertableJsonString.php
PHPUnit::assertEquals(
    json_encode($expected, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES),
    json_encode($actual, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
);

Как было отмечено ранее, json_encode преобразует экземпляр BackedEnum в его строковое значение, поэтому это утверждение пройдёт.

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