如何在测试期间禁用附加模型访问器?
How to disable appending model accessors during tests?
我正在编写一个测试,我需要使用 Faker factory builder
创建一个 Eloquent 模型 Video
的新实例
$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]: General error: 1 table videos has no column named 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
table 迁移
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
但是每次我附加另一个访问器时我都必须修改测试
您可以在关系中使用 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);
我还发现工厂构建器有一个 raw
方法,它只 returns 模型工厂中定义的数组
$user = create(User::class);
$video = create(Video::class, 'raw');
$user->videos()->create($video);
不需要序列化,raw
已经是数组
我正在编写一个测试,我需要使用 Faker factory builder
创建一个 Eloquent 模型Video
的新实例
$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]: General error: 1 table videos has no column named 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
table 迁移
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
但是每次我附加另一个访问器时我都必须修改测试
您可以在关系中使用 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);
我还发现工厂构建器有一个 raw
方法,它只 returns 模型工厂中定义的数组
$user = create(User::class);
$video = create(Video::class, 'raw');
$user->videos()->create($video);
不需要序列化,raw
已经是数组