codenco-dev / eloquent-model-tester
简化您的 Laravel 项目中 Eloquent 模型的测试
Requires
- php: ^8.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0
Requires (Dev)
- orchestra/testbench: ^6.0 || ^7.0 || ^8.0 || ^9.0
- phpunit/phpunit: ^9.0|^10.0|^11.0
README
此包允许您测试您的模型关于表结构、关系等
安装
您可以通过 composer 安装此包
composer require codenco-dev/eloquent-model-tester --dev
用法
要使用此包,您必须为您模型生成工厂。(见 工厂文档)您可以为单个模型或多个模型生成一个测试文件。例如,对于您的模型 MyModel
,您可以使用以下命令
php artisan make:model MyModel -mf php artisan make:test Models/MyModelTest
为了能够测试数据库,别忘了使用 RefreshDatabase
语句。
namespace Tests\Feature\Models;
use App\MyModel;
use CodencoDev\EloquentModelTester\HasModelTester;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class MyModelTest extends TestCase
{
use RefreshDatabase;
use HasModelTester;
public function test_have_my_model_model()
{
//...
}
}
为了更简单,您可以将 RefreshDatabase
使用语句放入 tests/TestCase.php
文件
结构和填充/保护测试
有这个结构
users
id - integer
name - string
email - string
password - string
remember_token - string
other_field - string
created_at - timestamp
updated_at - timestamp
您可以测试是否拥有所有需要的字段以及它们是否可填充或受保护。
class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasColumns(['id','name','email','password','remember_token']) ->assertHasColumnsInFillable(['name','password']) ->assertHasColumnsInGuarded(['remember_token']) ->assertHasTimestampsColumns(); } }
assertHasColumns()
函数仅检查提供的值是否在表的架构中。如果您想确保没有其他列存在,您可以使用更严格的 assertHasOnlyColumns()
断言来检查只存在提供的列名。
注意。当使用此功能时,如果您数据库表中存在 created_at
和 updated_at
字段,您需要提供这些字段。
assertHasColumnsInFillable()
和 assertHasColumnsInGuarded()
函数仅检查 $fillable
和 $guarded
数组中是否包含传递的值。如果您想确保 $fillable
和 $guarded
数组中没有其他条目,则可以使用更严格的 assertHasOnlyColumnsInFillable()
和 assetHasOnlyColumnsInGuarded()
函数,如下所示
class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasOnlyColumns(['id','name','email','password','remember_token', 'created_at', 'updated_at']) // Will fail as missing 'other_field'. ->assertHasOnlyColumnsInFillable(['name','password']) ->assertHasOnlyColumnsInGuarded(['remember_token']); } }
为了进一步确认只有一组列可以填充,您可以使用 assertCanOnlyFill()
断言来确认。此断言通过确认这些字段是 $fillable
数组中的唯一值,并且它们不出现在 $guarded
数组中来确认这一点。
class User extends Model { $fillable = ['name', 'password', 'email']; $guarded = ['remember_token']; } class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasColumns(['id','name','email','password','remember_token']) ->assertCanOnlyFill(['name','password']); // Will fail as 'email' is in the fillable array. } }
为了确认一个字段由于错误而同时出现在 $fillable
和 $guarded
数组中,有 assertNoGuardedAndFillableFields()
断言来检查没有条目同时出现在两者中
class User extends Model { $fillable = ['name', 'password', 'email']; $guarded = ['email']; } class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertNoGuardedAndFillableFields(); // Will fail as 'email' is in both the fillable & guarded arrays. } }
要检查模型上的软删除 deleted_at
列,可以使用 assertHasSoftDeleteTimestampColumns()
断言
user:
id - integer
name - string
deleted_at - timestamp
use Illuminate\Database\Eloquent\SoftDeletes; class User extends Model { use SoftDeletes; } class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasSoftDeleteTimestampColumns(); } }
HasOne 和 BelongsTo
您可以测试模型的关系。例如,有这个结构
user
id - integer
name - string
phones
id - integer
number - string
user_id - integer
您可以使用 assertHasHasOneRelation()
和 assertHasBelongsToRelations
方法如下
class UserTest extends TestCase { use HasModelTestor; public function test_have_category_model() { $this->modelTestable(User::class) ->assertHasHasOneRelation(Phone::class); } } class PhoneTest extends TestCase { use HasModelTestor; public function test_have_customer_model() { $this->modelTestable(Phone::class) ->assertHasBelongsToRelation(User::class); } }
HasMany 和 BelongsTo
您可以测试模型的关系。例如,有这个结构
categories
id - integer
name - string
customers
id - integer
name - string
category_id - integer
type_id - integer
您可以使用 assertHasHasManyRelations
和 assertHasBelongsToRelations
方法如下
class CategoryTest extends TestCase { use HasModelTestor; public function test_have_category_model() { $this->modelTestable(Category::class) ->assertHasHasManyRelation(Customer::class); } } class CustomerTest extends TestCase { use HasModelTestor; public function test_have_customer_model() { $this->modelTestable(Customer::class) ->assertHasBelongsToRelation(Category::class); } }
如果您不使用 Laravel 命名约定,您也可以通过向 assertHasHasManyRelations
和 assertHasBelongsToRelations
方法传递额外的参数来覆盖关系和本地键(对于 belongsTo 关系)
$this->modelTestable(Customer::class) ->assertHasBelongsToRelation(Category::class,'category','category_id'); $this->modelTestable(Category::class) ->assertHasHasManyRelation(Customer::class,'customers');
如果您有多个关系,您可以使用如下方式链式调用方法
$this->modelTestable(Customer::class) ->assertHasBelongsToRelation(Category::class) ->assertHasBelongsToRelation(OtherModel::class);
HasManyThrough 关系
您可以测试模型上 has many through 关系。例如,有这个结构
customers
id - integer
name - string
locations
id - integer
customer_id - integer
orders
id - integer
location_id - integer
您可以使用 assertHasHasManyThroughRelations
方法如下
class CustomersTest extends TestCase { use HasModelTestor; public function test_have_orders_model() { $this->modelTestable(Customer::class) ->assertHasHasManyThroughRelation(Order::class, Location::class); } }
如果您不使用 Laravel 命名约定,您也可以通过向 assertHasHasManyThroughRelations
方法传递额外的参数来覆盖关系和外部键
$this->modelTestable(Customer::class) ->assertHasHasManyThroughRelation(Order::class, Location::class, 'sales', 'prefix_customer_id', 'prefix_location_id', 'firstPrimaryKey', 'secondPrimaryKey');
注意:由于这个关系没有官方的逆关系,因此不能在反向使用这个断言,即在 orders
模型检查 customers
关系时。
多对多关系
您可以使用 ManyToManyRelationsTestable
特性来测试您的多对多关系。
users
id - integer
name - string
roles
id - integer
name - string
role_user
user_id - integer
role_id - integer
class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasManyToManyRelation(Role::class); } } class RoleTest extends TestCase { use HasModelTestor; public function test_have_role_model() { $this->modelTestable(User::class) ->assertHasManyToManyRelation(User::class); } }
您也可以重写关系参数。
$this->modelTestable(User::class) ->assertHasManyToManyRelation(User::class,'users');
形态关系
如果您有一个形态关系,
posts
id - integer
title - string
body - text
videos
id - integer
title - string
url - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string
您可以使用如下方式使用 assertHasBelongsToMorphRelations
和 assertHasHasManyMorphRelations
方法
class PostTest extends TestCase { use HasModelTestor; public function test_have_post_model() { $this->modelTestable(Post::class) ->assertHasHasManyMorphRelation(Comment::class,'comments'); } } class VideoTest extends TestCase { use HasModelTestor; public function test_have_video_model() { $this->modelTestable(Video::class) ->assertHasHasManyMorphRelation(Comment::class,'comments'); } } class CommentTest extends TestCase { use HasModelTestor; public function test_have_morph_model_model() { $this->modelTestable(Comment::class) ->assertHasBelongsToMorphRelation(Post::class,'commentable') ->assertHasBelongsToMorphRelation(Video::class,'commentable'); } }
形态一对一关系
如果您有一个形态一对一关系,
posts
id - integer
title - string
body - text
users
id - integer
title - string
images
id - integer
url - string
imageable_id - integer
imageable_type - string
您可以使用如下方式使用 assertHasBelongsToMorphRelations
和 assertHasMorphOneRelations
方法
class PostTest extends TestCase { use HasModelTestor; public function test_have_post_model() { $this->modelTestable(Post::class) ->assertHasMorphOneRelation(Image::class); } } class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasMorphOneRelation(Image::class, 'avatar'); } } class ImageTest extends TestCase { use HasModelTestor; public function test_have_image_model() { $this->modelTestable(Image::class) ->assertHasBelongsToMorphRelation(Post::class,'imageable') ->assertHasBelongsToMorphRelation(User::class,'imageable'); } }
没有模型的主表和从表
您可以使用 tableTestable
方法测试一个表是否包含具有的列。
class MyPivotTest extends TestCase { public function test_have_table_without_model() { $this->tableTestable('pivot_table') ->assertHasColumns(['first_model_id','second_model_id','other_property']); } }
模型作用域
您可以使用 assertHasScope()
断言来测试一个模型是否定义了查询作用域。
class User extends Model { /** * Scope a query to only include popular users. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopePopular($query) { return $query->where('votes', '>', 100); } } class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasScope('popular'); } }
当然,如果您使用动态作用域,则 assertHasScope()
接收传递给查询作用域的参数。
class User extends Model { /** * Scope a query to only include users of a given type. * * @param \Illuminate\Database\Eloquent\Builder $query * @param mixed $type * @return \Illuminate\Database\Eloquent\Builder */ public function scopeOfType($query, $type) { return $query->where('type', $type); } } class UserTest extends TestCase { use HasModelTestor; public function test_have_user_model() { $this->modelTestable(User::class) ->assertHasScope('ofType', 'admin'); } }
可用的断言
测试
composer test
变更日志
有关最近更改的更多信息,请参阅 变更日志。
贡献
有关详细信息,请参阅 贡献指南。
安全性
如果您发现任何安全问题,请通过电子邮件 dthomas@codenco.fr 或在 Twitter 上联系我 DomThomasEs,而不是使用问题跟踪器。
鸣谢
许可
MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件。
Laravel 包模板
此包是使用 Laravel 包模板 生成的。