Database Testing

    Laravel 提供了各种有用的工具,可以更轻松地测试数据库驱动的应用程序。 首先,您可以使用 帮助程序断言数据库中存在的数据与给定的一组条件匹配。 例如,如果您要验证 users 表中的记录是否具有 sally @ example.comemail 值,您可以执行以下操作:

    您还可以使用 assertDatabaseMissing 帮助程序断言数据库中不存在数据。

    assertDatabaseHas 方法和其他类似的帮助程序是为了方便起见。 您可以自由使用任何 PHPUnit 的内置断言方法来补充您的测试。

    生成模型工厂

    使用 make:factory 命令可以创建一个模型工厂:

    1. php artisan make:factory PostFactory

    新生成的工厂位置在 database/factories 目录下。

    —model 选项可用于指示工厂创建的模型的名称。 此选项将使用给定模型预填充生成的工厂文件:

    1. php artisan make:factory PostFactory --model=Post

    在每次测试后重置数据库通常很有用,这样前一次测试的数据不会干扰后续测试。 RefreshDatabase 特征采用最优化的方法来迁移测试数据库,具体取决于您使用的是内存数据库还是传统数据库。 在测试类上使用特征,一切都将为您处理:

    1. <?php
    2. namespace Tests\Feature;
    3. use Tests\TestCase;
    4. use Illuminate\Foundation\Testing\RefreshDatabase;
    5. use Illuminate\Foundation\Testing\WithoutMiddleware;
    6. class ExampleTest extends TestCase
    7. {
    8. use RefreshDatabase;
    9. /**
    10. * 一个基本功能测试示例
    11. *
    12. */
    13. public function testBasicExample()
    14. {
    15. $response = $this->get('/');
    16. // ...
    17. }
    18. }

    创建模型工厂

    测试时,您可能需要在执行测试之前将几条记录插入数据库。 在创建此测试数据时, Laravel 不是手动指定每列的值,而是允许您使用模型工厂为每个 定义一组默认属性。 开始测试前,请查看应用程序中的 database / factories / UserFactory.php 文件。 开箱即用,此文件包含一个工厂定义:

    1. use Illuminate\Support\Str;
    2. use Faker\Generator as Faker;
    3. $factory->define(App\User::class, function (Faker $faker) {
    4. return [
    5. 'name' => $faker->name,
    6. 'email' => $faker->unique()->safeEmail,
    7. 'email_verified_at' => now(),
    8. 'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
    9. ];
    10. });

    您还可以为每个模型创建其他工厂文件,以便更好地进行组织。 例如,您可以在 database / factories 目录中创建 UserFactory.phpCommentFactory.php 文件。 factories 目录中的所有文件都将由 Laravel 自动加载。

    States 允许您定义可以任意组合应用于模型工厂的离散修改。 例如,您的 User模型可能具有 deinquent 状态,可以修改其默认属性值之一。 您可以使用 state 方法定义状态转换。 对于简单状态,您可以传递一组属性修改:

    1. $factory->state(App\User::class, 'delinquent', [
    2. 'account_status' => 'delinquent',
    3. ]);

    如果你的状态需要计算或 $ faker 实例,你可以使用 Closure 来计算状态的属性修改:

    使用 afterMakingafterCreating 方法注册工厂回调,并允许您在创建或创建模型后执行其他任务。 例如,您可以使用回调将其他模型与创建的模型相关联:

    1. $factory->afterMaking(App\User::class, function ($user, $faker) {
    2. // ...
    3. });
    4. $factory->afterCreating(App\User::class, function ($user, $faker) {
    5. $user->accounts()->save(factory(App\Account::class)->make());
    6. });

    您还可以为 工厂状态 定义回调:

    1. $factory->afterMakingState(App\User::class, 'delinquent', function ($user, $faker) {
    2. // ...
    3. });
    4. $factory->afterCreatingState(App\User::class, 'delinquent', function ($user, $faker) {
    5. // ...
    6. });

    模型工厂定义后,就可以在测试或种子文件中使用全局 factory 函数来生成模型实例。 那么,让我们来看一些创建模型的例子。 首先,我们将使用 make 方法创建模型,但不将它们保存到数据库中:

    1. public function testDatabase()
    2. {
    3. $user = factory(App\User::class)->make();
    4. //在测试中使用模型...
    1. //创建三个 App\User 实例...
    2. $users = factory(App\User::class, 3)->make();

    应用状态

    您也可以将任何 states 应用于模型。 如果要将多个状态转换应用于模型,则应指定要应用的每个状态的名称:

    1. $users = factory(App\User::class, 5)->states('delinquent')->make();
    2. $users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();

    覆盖属性

    如果要覆盖模型的某些默认值,可以将一组值传递给 make 方法。 只有指定的值才会被替换,而其余值仍然设置为工厂指定的默认值:

    方法不仅创建了模型实例,还使用Eloquent的 save 方法将它们保存到数据库中:

    1. public function testDatabase()
    2. {
    3. // 创建单个 App\User 实例...
    4. $user = factory(App\User::class)->create();
    5. // 创建3个 App\User 实例..
    6. $users = factory(App\User::class, 3)->create();
    7. // 在测试中使用模型...
    8. }

    您可以通过将数组传递给 create 方法来覆盖模型上的属性:

    1. $user = factory(App\User::class)->create([
    2. 'name' => 'Abigail',
    3. ]);

    在这个例子中,我们将附加一些创建模型的关系。 当使用 create 方法创建多个模型时,返回一个 Eloquent 集合实例 ,这样就可以在集合上使用 each 等便利方法:

    1. $users = factory(App\User::class, 3)
    2. ->create()
    3. ->each(function ($user) {
    4. $user->posts()->save(factory(App\Post::class)->make());
    5. });

    关联 & 属性闭包

    您还可以使用工厂定义中的 Closure 属性将关系附加到模型。 例如,如果您想在创建 Post 时创建一个新的 User 实例,您可以执行以下操作:

    1. $factory->define(App\Post::class, function ($faker) {
    2. return [
    3. 'title' => $faker->title,
    4. 'content' => $faker->paragraph,
    5. 'user_id' => function () {
    6. return factory(App\User::class)->create()->id;
    7. }
    8. ];
    9. });

    这些闭包接收一个包含工厂属性的数组:

    1. $factory->define(App\Post::class, function ($faker) {
    2. return [
    3. 'title' => $faker->title,
    4. 'content' => $faker->paragraph,
    5. 'user_id' => function () {
    6. return factory(App\User::class)->create()->id;
    7. },
    8. 'user_type' => function (array $post) {
    9. return App\User::find($post['user_id'])->type;
    10. }
    11. });

    可用的断言方法

    Laravel 为 PHPUnit 测试提供了多个数据库断言方法:

    本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接 我们的翻译工作遵照 ,如果我们的工作有侵犯到您的权益,请及时联系我们。