[ Laravel 5.7 文档 ] 测试系列 —— 数据库测试

文章来源: http://laravelacademy.org/post/9594.html, 本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

简介

Laravel 提供了多个有用的 工具 让测试 数据库 驱动的应用变得更加简单。首先,你可以使用辅助函数 assertDatabaseHas 来断言数据库中的数据是否和给定数据集合匹配。例如,如果你想要通过 email 值为 xueyuanjun@laravelacademy.org 的条件去数据表 users 查询是否存在该记录 ,我们可以这样做:

public function testDatabase()
{
    // Make call to application...

    $this->assertDatabaseHas('users', [
        'email' => 'xueyuanjun@laravelacademy.org'
    ]);
}

你还可以使用 assertDatabaseMissing 辅助函数断言数据在数据库中不存在。

当然, assertDatabaseHas 方法和其它类似辅助方法都是为了方便起见进行的封装,你也可以使用其它 PHPUnit 内置的断言方法来进行测试。

生成模型工厂

模型工厂可用于快速填充数据表。要创建一个模型工厂,可以使用Artisan 命令 make:factory

php artisan make:factory PostFactory

新创建的工厂类位于 database/factories 目录下。

--model 选项可用于指示模型工厂对应的模型类。该选项通过给定的模型名称预填充生成的工厂类:

php artisan make:factory PostFactory --model=Post

生成的 PostFactory 内容如下:

<?php

use Faker\Generator as Faker;

$factory->define(App\Post::class, function (Faker $faker) {
    return [
        //
    ];
});

每次测试后重置数据库

每次测试后重置数据库通常很有用,这样的话上次测试的数据不会影响下一次测试。 RefreshDatabase trait 基于你是用的是内存数据库还是关系数据库使用最优方式来迁移测试数据库。在测试类上使用这个 trait,一切都不需要操心,系统会自动帮你在每次测试后重置数据库:

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    use RefreshDatabase;

    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->get('/');

        // ...
    }
}

编写工厂

测试时,通常需要在执行测试前插入新数据到数据库。在创建测试数据时,Laravel 允许你使用模型工厂为每个Eloquent 模型定义默认的属性值集合,而不用手动为每一列指定值。作为开始,我们看一下 database/factories/ModelFactory.php 文件,该文件包含了一个工厂定义:

use Faker\Generator as Faker;

$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
        'remember_token' => str_random(10),
    ];
});

在闭包中,作为工厂定义,我们返回该模型上所有属性默认测试值。该闭包接收 PHPFaker 实例,从而允许你方便地为测试生成多种类型的随机数据。

你还可以为每个模型创建额外的工厂文件以便更好地组织管理,例如,你可以在 database/factories 目录下创建 UserFactory.phpCommentFactory.php 文件。 factories 目录下的所有文件都会被Laravel 自动加载。

注:你可以通过添加 faker_locale 配置项到 config/app.php 配置文件来设置 Faker 的本地化。

工厂状态

状态允许你在任意组合中定义可用于模型工厂的离散修改,例如, User 模型可能有一个 delinquent 状态用于修改某个默认属性值,你可以使用 state 方法来定义状态转化。对于简单的状态,可以传递一个属性修改数组:

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

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

$factory->state(App\User::class, 'address', function ($faker) {
    return [
        'address' => $faker->address,
    ];
});

工厂回调

工厂回调通过 afterMakingafterCreating 方法注册,允许你在创建工厂后执行额外的任务,例如,你可以使用回调来关联额外的模型到已创建的模型:

$factory->afterMaking(App\User::class, function ($user, $faker) {
    // ...
});

$factory->afterCreating(App\User::class, function ($user, $faker) {
    $user->accounts()->save(factory(App\Account::class)->make());
});

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

$factory->afterMakingState(App\User::class, 'delinquent', function ($user, $faker) {
    // ...
});

$factory->afterCreatingState(App\User::class, 'delinquent', function ($user, $faker) {
    // ...
});

使用工厂

创建模型

定义好工厂后,可以在测试或数据库填充文件中通过全局的 factory 方法使用它们来生成模型实例,所以,让我们看一些创建模型的例子,首先,我们使用 make 方法,该方法创建模型但不将其保存到数据库:

public function testDatabase(){
    $user = factory(App\User::class)->make();
    // 用户模型测试...
}

还可以创建多个模型集合或者创建给定类型的模型:

// 创建3个 App\User 实例...
$users = factory(App\User::class, 3)->make();

应用状态

还可以应用任意状态到模型,如果你想要应用多个状态转化到模型,需要指定每个你想要应用的状态名:

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

覆盖属性

如果你想要覆盖模型中的某些默认值,可以传递数组值到 make 方法,只有指定值才会被替换,剩下值保持工厂指定的默认值不变:

$user = factory(App\User::class)->make([
    'name' => 'Abigail',
]);

持久化模型

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

public function testDatabase()
{
    // 创建单个 App\User 实例...
    $user = factory(App\User::class)->create();

    // 创建3个 App\User 实例...
    $users = factory(App\User::class, 3)->create();

    // 在测试中使用模型...
}

你可以通过传递数组到 create 方法覆盖模型上的属性:

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

关联关系

在本例中,我们添加一个关联到创建的模型,使用 create 方法创建多个模型的时候,会返回一个 Eloquent集合实例,从而允许你使用集合提供的所有方法,例如 each

$users = factory(App\User::class, 3)
           ->create()
           ->each(function($u) {
                $u->posts()->save(factory(App\Post::class)->make());
            });

关联关系 & 属性闭包

还可以使用工厂中的闭包属性添加关联关系到模型,例如,如果你想要在创建 Post 的时候创建一个新的 User 实例,可以这么做:

$factory->define(App\Post::class, function ($faker) {
    return [
        'title' => $faker->title,
        'content' => $faker->paragraph,
        'user_id' => function () {
            return factory(App\User::class)->create()->id;
        }
    ];
});

这些闭包还接收包含它们的工厂属性数组:

$factory->define(App\Post::class, function ($faker) {
    return [
        'title' => $faker->title,
        'content' => $faker->paragraph,
        'user_id' => function () {
            return factory(App\User::class)->create()->id;
        },
        'user_type' => function (array $post) {
            return App\User::find($post['user_id'])->type;
        }
    ];
});

有效的断言方法

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

方法 描述
$this->assertDatabaseHas($table, array $data); 断言数据表包含给定数据
$this->assertDatabaseMissing($table, array $data); 断言数据表不包含给定数据
$this->assertSoftDeleted($table, array $data); 断言给定记录已经被软删除

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

为你推荐:

查看所有标签

码农书籍
深入理解C++11:C++11新特性解析与应用

深入理解C++11:C++11新特性解析与应用

Michael Wong、IBM XL编译器中国开发团队 / 机械工业出版社 / 2013-6 / 69.00元

《深入理解C++11:C++11新特性解析与应用》内容简介:国内首本全面深入解读C++11新标准的专著,由C++标准委员会代表和IBMXL编译器中国开发团队共同撰写。不仅详细阐述了C++11标准的设计原则,而且系统地讲解了C++11新标准中的所有新语言特性、新标准库特性、对原有特性的改进,以及如何应用所有这些新特性。《深入理解C++11:C++11新特性解析与应用》一共8章:第1章从设计思维和应用范畴两个维度对C++11新标准中的所有特性进行了分类,呈现了C++11新特性的原貌;第2章讲解了在保证与C语言和旧版C++标准充分兼容的原则下增加的一些新特性;第3章讲解了具有广泛可用性、能与其他已有的或者新增的特性结合起来使用的、具有普适性的一些新特性;第4章讲解了C++11新标准对原有一些语言特性的改进,这些特性不仅能让C++变得更强大,还能提升程序...

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具