Лучший способ обработать статус / состояние отношения модели при модульном тестировании в Laravel 6? - PullRequest
0 голосов
/ 07 марта 2020

У меня есть следующий модульный тест в Laravel 6.x с использованием SQLite:

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Entry;
use App\EntryStatus;
use Faker\Generator as Faker;

$factory->define(Entry::class, function (Faker $faker) {
    return [
        'user_id' => 1,
        'caption' => $faker->sentence(10),
        'entry_status_id' => EntryStatus::where('name', 'pending')->first()->id,
    ];
});

$factory->state(Entry::class, 'awaiting_payment', [
    'entry_status' => EntryStatus::where('name', 'awaiting_payment')->first()->id,
]);

У меня есть тестовая ошибка «Попытка получить свойство« id »не-объекта», которая для следующей строки:

'entry_status' => EntryStatus::where('name', 'awaiting_payment')->first()->id,

У меня есть несколько идей о том, как исправить эту ошибку, но мне интересно, какова будет лучшая практика с точки зрения модульного тестирования и 'Laravel way '.

Как я об этом думал, у меня есть таблица EntryStatus, в которой есть stati c statues' pending '=> 0,' awaiting_payment '=> 1,' paid '=> 2 et c. И я создаю связь в моей модели App \ Entry> App \ EntryStatus. Идеи заключаются в следующем:

  1. Первоначальный план; для модульных тестов мне нужно заполнять таблицу stati c EntryStatus каждый раз для каждого теста. Глядя на документы, я бы использовал что-то вроде setUp ()> $ this-> artisan ('db: seed'). Но похоже, что это действительно замедлит тесты. Если нет способа заполнить базу данных один раз, прежде чем начнутся все тесты.

  2. Попробуйте создать фабрику, которая создает данные о состоянии c ('pending' => 0, 'awaiting_payment) '=> 1) но мне нужно было бы вручную обновлять начальное число базы данных и фабрику каждый раз, чтобы соответствовать, что кажется неуклюжим.

  3. В документах для проверки документов Laravel они имеют это пример; $ factory-> state (App \ User :: class, 'delinquent', ['account_status' => 'delinquent',]). Это заставляет меня думать, что я могу просто полностью удалить таблицу отношений EntryStatus и просто использовать строковый столбец в Entry для представления состояния. Я думаю, что это было бы лучшим решением, но я беспокоюсь, что есть причина, по которой мы используем идентификаторы в качестве статусов, так как я думаю, что они быстрее в поисковых запросах. Но если нет, мои статуи будут исправлены, и это кажется самым красноречивым решением.

Другой вариант - в любом случае хранить статуи как целые, сохраняя при этом информацию о статусе. какое целое число, но опять же это не кажется правильным.

1 Ответ

1 голос
/ 08 марта 2020

Запись еще не создана, поэтому не рекомендуется назначать отношения stati c таким образом на фабриках.

Вместо этого можно использовать фабрику create, а затем назначить отношения внутри тестового примера. .

Например:

Entry фабрика

$factory->define(Entry::class, function (Faker $faker) {
    return [
        'user_id' => factory(User)->create()->id,
        'caption' => $faker->sentence(10),
        'entry_status_id' => factory(EntryStatus)->create()->id,
    ];
});

EntryStatus фабрика

$factory->define(EntryStatus::class, function (Faker $faker) {
    return [
        'name' => $faker->word,
        'entry_status' => $faker->numberBetween(0, 2) //Its better start from 1 though
    ];
});

User фабрика

$factory->define(User::class, function (Faker $faker) {
    return [
        'name' => $faker->word
    ];
});

В вашем тестовом примере начните связывать вещи вместе (если вам нужно).

/**
 * @test
 */
public function exampleTestCase()
{
    $enteryStatus = factory(EntryStatus::class)->create(['entry_status' => 1]);

    //create 6 entries
    $entry = factory(Entry::class, 6)->create(['entry_status_id' => $enteryStatus->id]);

    //TODO: assert something
}

Вы можете проверить afterCreatingState

$factory
    ->state(EntryStatus::class, 'awaiting_payment', ['name' => 'awaiting_payment'])
    ->afterCreatingState(EntryStatus::class, 'awaiting_payment', function ($entryStatus, $faker) {
        factory(Entry::class)->create([
            'entry_status_id' => $entryStatus->id,
        ]);
    });
...