Как отключить добавление моделей доступа во время тестов? - PullRequest
0 голосов
/ 23 октября 2019

Пишу тест, в котором мне нужно создать новый экземпляр модели Eloquent Video с использованием Faker Factory Builder

$user = create(User::class);
$video = create(Video::class, 'make')->toArray(); // toArray serializes the model to include accessors
$user->videos()->create($video); // <--- Error occurs here

PDOException: SQLSTATE [HY000]: общая ошибка: 1 таблицау видео нет столбца с именем views

create() - это обертка вспомогательной функции вокруг factory() в автоматически загружаемом файле

/**
 * Generate a fake model
 *
 * Call the factory helper function on given model
 *
 * @param Illuminate\Database\Eloquent\Model $model Eloquent Model
 * @param string $method create or make the model
 * @param int $times How many model instances to return
 * @param array $properties Model attributes to override in factory
 *
 * @return mixed Illuminate\Database\Eloquent\Model|array|collection
 **/
function create($model, $method = 'create', $times = null, $properties = [])
{
    return factory($model, $times)->$method($properties);
}

Модель Video добавляет viewsаксессор (не связанный с базой данных), вот модель

class Video extends BaseModel
{
    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = ['views', 'length', 'timesReported'];
}

Аксессор views находится в BaseModel, вот что

class BaseModel extends Model
{
    public $guarded = []; // Yolo!!

    /**
     * Get the user who owns the model.
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }

    // Get model views count from Redis
    public function getViewsAttribute()
    {
        return \Redis::zscore('popular_'.$this->getTable(), $this->id);
    }
}

Вот VideoFactory на случай, если этополезно

$factory->define(App\Video::class, function (Faker $faker) {
    return [
        'title' => $faker->realText(50, 2),
        'uploader' => 'Unknown',
        'duration' => '00:00:00',
        'thumbnail' => $faker->imageUrl(),
        'poster' => $faker->imageUrl(),
        'slides' => $faker->imageUrl(),
        'hls' => $faker->url,
        'mp4' => $faker->url,
        '_3gp' => $faker->url,
        'quality' => $faker->randomElement(['normal', 'hd']),
    ];
});

и миграция таблицы videos

Schema::create('videos', function (Blueprint $table) {
    $table->increments('id');
    $table->json('title'); // MySQL doesn't allow uniqueness on json type columns
    $table->enum('quality', ['normal', 'hd']);
    $table->unsignedInteger('user_id');
    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    $table->string('uploader');
    $table->time('duration');
    $table->string('thumbnail')->unique();
    $table->string('poster')->unique();
    $table->string('slides')->unique();
    $table->string('hls')->unique();
    $table->string('mp4', 350)->unique();
    $table->string('_3gp', 350)->unique();
    $table->json('slug');
    $table->timestamps();
});

Как исключить добавленные методы доступа к вызовам фабрики моделей?

Я думал об использовании array_except, нотогда мне придется изменять тест каждый раз, когда я добавляю другой метод доступа

Ответы [ 2 ]

1 голос
/ 23 октября 2019

Я также обнаружил, что у фабричного сборщика есть метод raw, который возвращает только массив, определенный на фабрике моделей

$user = create(User::class);
$video = create(Video::class, 'raw');
$user->videos()->create($video);

Нет необходимости сериализовать, raw уже является массивом

1 голос
/ 23 октября 2019

Вы можете использовать save вместо create в отношениях, поскольку у вас уже есть экземпляр Video с атрибутами, которые вы хотели получить с завода:

$user = create(User::class);
$video = create(Video::class, 'make');
$user->videos()->save($video);

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

Если вы действительно хотите использовать create в этих отношениях, чтоозначает, что вам нужно передать атрибуты на create, вы можете вызвать getAttributes вместо toArray():

$video = create(Video::class, 'make')->getAttributes();
$user->videos()->create($video);
...