Laravel
February 17

Размышления об уникальности в фабриках

Как много уникальности вам нужно?

Некоторые участники сообщества Mastering Laravel столкнулись с проблемой, связанной с фабриками, когда время от времени создавались две модели с одинаковым значением свойства, что приводило к сбоям в работе тестов.

Возник вопрос: как предотвратить подобные случайные сбои в тестировании?

Короткий ответ — использовать модификатор unique(), предоставляемый `Faker, для предотвращения совпадения этих значений, но есть и более тонкий подход, которым я хочу поделиться.

Рассмотрим на конкретном примере, чтобы было понятнее. У нас есть модель `User со свойствами first_name и last_name.

И только в одном или двух тестах требуется убедиться, что фабрика генерирует уникальные значения для этих свойств.

Не рекомендую использовать цепочку unique() для этих свойств в определении фабрики по умолчанию. Почему? Уникальность нужна только нескольким тестам, а добавление этого модификатора добавляет накладные расходы при каждом использовании.

Я бы добавил unique() в определение по умолчанию только в том случае, если схема базы данных требует уникальности. Тогда это основное требование приложения.

Так что же можно сделать вместо этого? Если это всего лишь один или два теста, я бы сделал это прямо внутри теста при вызове фабрики:

User::factory()->create([
    'first_name' => $this->faker->unique()->firstName,
    'last_name' => $this->faker->unique()->lastName,
]);

Если это необходимо более чем в паре тестов, можно пойти дальше и создать новое состояние в фабрике:

// в UserFactory.php
public function uniqueNames()
{
    return $this->state([
        'first_name' => $this->faker->unique()->firstName,
        'last_name' => $this->faker->unique()->lastName,
    ]);
}

// затем в тесте
User::factory()->uniqueNames()->create();