Laravel 测试教程

参考链接:https://laravel-news.com/seeding-data-testing

迁移文件

修改 database/migrations/2014_10_12_000000_create_users_table.php

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

        // following table is storing the relationship between users
        // user_id is following follow_user_id
        Schema::create('following', function (Blueprint $table) {
            $table->integer('user_id')->unsigned()->index();
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

            $table->integer('follow_user_id')->unsigned()->index();
            $table->foreign('follow_user_id')->references('id')->on('users')->onDelete('cascade');

            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('following');
        Schema::dropIfExists('users');
    }
}

执行迁移

php artisan migrate
Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table

User Model

修改 app/User.php

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function follows(User $user)
    {
        $this->following()->attach($user->id);
    }

    public function unfollows(User $user)
    {
        $this->following()->detach($user->id);
    }

    public function following()
    {
        return $this->belongsToMany('App\User', 'following', 'user_id', 'follow_user_id')->withTimestamps();
    }

    public function isFollowing(User $user)
    {
        return !is_null($this->following()->where('follow_user_id', $user->id)->first());
    }
}

这里使用了多对多用户关系关联方法[1]

种子文件

创建一个种子文件 database/seeds/UsersTableSeeder.php

php artisan make:seeder UsersTableSeeder

在种子文件中使用工厂方法[2]

use App\User;
use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $users = factory(User::class, 10)->create();
    }
}

执行种子文件

  1. 方式一
php artisan db:seed --class=UsersTableSeeder
  1. 方式二

database/seeds/DatabaseSeeder.php 中注册种子文件

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UsersTableSeeder::class);
    }
}

执行这个 DatabaseSeeder 这个大种子。

php artisan db:seed

测试用例

创建一个测试用例。

php artisan make:test Feature\UserTest

修改 tests/Feature/UserTest.php 的内容。

use App\User;

class UserTest extends TestCase
{
    public function test_have_10_users()
    {
        $this->assertEquals(10, User::count());
    }
}

执行测试

vendor\bin\phpunit

完整的测试文件

<?php

use App\User;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class UserTest extends TestCase
{

    use DatabaseTransactions;

    public function test_follows()
    {
        $userA = User::find(2);
        $userB = User::find(3);

        $userA->follows($userB);

        $this->assertEquals(1, $userA->following()->count());
    }

    public function test_unfollows()
    {
        $userA = User::find(3);
        $userB = User::find(2);

        $userA->unfollows($userB);

        $this->assertEquals(0, $userA->following()->count());
    }

    public function test_A_follows_B_and_C()
    {
        $userA = User::find(1);

        $ids = collect([2, 3, 4, 5, 6, 7, 8, 9, 10]);
        $random_ids = $ids->random(2);

        $userB = User::find($random_ids->pop());
        $userC = User::find($random_ids->pop());

        $userA->follows($userB);
        $userA->follows($userC);

        $this->assertEquals(2, $userA->following()->count());
    }
}

每执行一次测试,都会在数据库表中插入数据。因此这一次运行结果和前一次可能不一样

我们不得不像下面这样,每执行一次测试,就得重新 refresh & seeding吗?

php artisan migrate:refresh --seed
vendor\bin\phpunit

不用!加上 DatabaseTransactions 就好了。

class UserTest extends TestCase
{
    use DatabaseTransactions;

    ...
}

这个 Trait 将所有测试项放在一个事务中。无论执行结果如何(全部成功或者没全部成功)都不会对之前的数据库数据造成任何影响,也就是说这个事务在最后总是回滚

tags: Laravel 项目

  1. belongsToMany 方法用来定义多对多关系。它的第一个参数是关联表(这里是自关联,用户关注用户);第二个参数是中间表名(这里定义为 following);第三个参数是 $this 指代的 Model 的主键在中间表里的字段名;第四个参数是对应表(这里指被关注的人,对应的还是 users 表)的主键在中间表里的字段名。 ↩︎

  2. 工厂方法在 database/factories 下定义,可以定义在 ModelFactory.php 中,也可以定义在基于 Model 的工厂方法里(比如 UserFactory.php)。它们都会被 Laravel 处理。 ↩︎

posted @ 2017-05-05 16:54  Hi!张宝  阅读(1993)  评论(0编辑  收藏  举报