测试中数据播种简介
发布于 作者: Sky Chin
自从 Laravel 5.1 中发布了数据播种功能以来,测试变得更加容易和快捷。
您可以在测试开始之前插入十个用户,每个用户都有一个帖子,或者插入 1000 个用户,每个用户都有一个或多个帖子。
在本教程中,您将创建一个测试用例来测试用户模型,并创建一个播种器来将十个用户播种到数据库中,每个用户都关注一个用户。
首先,我们需要创建数据库表。
迁移
创建一个表来存储用户之间的关系(谁关注谁)。
# database/migrations/2014_10_12_000000_create_users_table.phpclass 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 migrateMigration table created successfully.
如果您的应用程序版本是 5.4,并且您看到了以下错误
[Illuminate\Database\QueryException] SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))[PDOException]SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
不要惊慌!查看这篇 文章 了解解决方法。
在应用了解决方法后,删除之前创建的表,然后再次运行迁移。
php artisan migrateMigration table created successfully.Migrated: 2014_10_12_000000_create_users_tableMigrated: 2014_10_12_100000_create_password_resets_table
数据库已准备就绪。现在,让我们准备用户模型。
用户模型
用户模型是本例中的测试对象,它有一些方法来创建和检索用户之间的关系。
# app/User.phpclass 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()); }}
用户模型已准备好进行测试。接下来,我们将数据插入数据库。
数据播种
Laravel 使执行数据播种变得非常容易。播种器类默认包含一个 run 方法。您可以使用查询构建器或 Eloquent 模型工厂来插入数据。
让我们运行一个 Artisan 命令来生成一个播种器。
php artisan make:seeder UsersTableSeeder
然后,您使用 模型工厂 在 run 方法中生成十个用户。
# database/seeds/UsersTableSeeder.phpuse 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(); }}
运行 Artisan 命令来执行数据播种。
php artisan db:seed --class=UsersTableSeeder
您也可以在 DatabaseSeeder 的 run 方法中启用对 UsersTableSeeder 的调用。
# database/seeds/UsersTableSeeder.phpuse 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(); }}
运行 Artisan 命令来执行数据播种。
php artisan db:seed --class=UsersTableSeeder
您也可以在 DatabaseSeeder 的 run 方法中启用对 UsersTableSeeder 的调用。
# database/seeds/DatabaseSeeder.phpclass DatabaseSeeder extends Seeder{ /** * Run the database seeds. * * @return void */ public function run() { $this->call(UsersTableSeeder::class); }}
接下来,运行命令而不声明播种器类名称。
php artisan db:seed
使用 DatabaseSeeder,您可以执行多个播种器类。
现在,我们将着手处理我们的测试用例。
测试用例
在本教程中,您的测试用例的目标是测试用户模型中的 follow 和 unfollow 方法。
我们将从生成一个新的测试开始。
php artisan make:test UserTest
先决条件测试
首先,我们将创建一个测试以确保数据库中有十个用户。
# tests/Feature/UserTest.phpuse App\User; class UserTest extends TestCase{ public function test_have_10_users() { $this->assertEquals(10, User::count()); }}
运行 PHPUnit。
phpunit
如果它不起作用,请尝试以下操作。
vendor/bin/phpunitPHPUnit 5.7.17 by Sebastian Bergmann and contributors.... 3 / 3 (100%)Time: 2.72 seconds, Memory: 12.00MBOK (3 tests, 3 assertions)
为什么 PHPUnit 不起作用?也许您的机器版本不符合 Laravel 的要求。Laravel 通过 Composer 预安装了 PHPUnit。您可以运行它。在我的情况下,vendor/bin/phpunit 工作正常。在接下来的教程中,我将使用 vendor/bin/phpunit。
测试
通过完成上一步,您确认数据播种和单元测试正常工作。它是创建真实测试的绿灯。
# tests/Feature/UserTest.phppublic function test_follows(){ $userA = User::find(2); $userB = User::find(3); $userA->follows($userB); $this->assertEquals(2, $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());}
再次运行 PHPUnit。
vendor\bin\phpunitPHPUnit 5.7.17 by Sebastian Bergmann and contributors....... 6 / 6 (100%)Time: 1.23 seconds, Memory: 10.00MBOK (6 tests, 6 assertions)
所有测试都通过了!酷!我建议您再次运行测试以测试一致性。
vendor\bin\phpunitPHPUnit 5.7.17 by Sebastian Bergmann and contributors...F.F. 6 / 6 (100%)Time: 1.25 seconds, Memory: 10.00MBThere were 2 failures:1) Tests\Feature\UserTest::test_followsFailed asserting that 3 matches expected 2.C:\xampp\htdocs\TestWithSeed\tests\Feature\UserTest.php:262) Tests\Feature\UserTest::test_A_follows_B_and_CFailed asserting that 4 matches expected 2.C:\xampp\htdocs\TestWithSeed\tests\Feature\UserTest.php:52 FAILURES!Tests: 6, Assertions: 6, Failures: 2.
糟糕!两个测试失败了。发生了什么事?
当您第一次运行测试时,测试已经对数据库中的数据进行了更改。因此,当您再次运行测试时,更改后的数据会影响测试结果。
这并不意味着应用程序有错误。测试用例有责任处理这种情况。我建议在每次测试运行之前重置数据库。
重置数据库
建议一,在 PHPUnit 之前运行迁移刷新和数据播种。
php artisan migrate:refresh --seedvendor\bin\phpunit
更好的建议是使用 Traits。Laravel 提供两种在每次测试后重置数据库的方法。它们是 DatabaseMigrations 和 DatabaseTransactions。
让我们尝试一下 DatabaseMigrations。
# tests/Feature/UserTest.phpclass UserTest extends TestCase{ use DatabaseTransactions; ...}
运行测试。
vendor\bin\phpunitPHPUnit 5.7.17 by Sebastian Bergmann and contributors. ..EEE. 6 / 6 (100%) Time: 5.53 seconds, Memory: 12.00MB There were 3 errors: 1) Tests\Feature\UserTest::test_followsError: Call to a member function follows() on null C:\xampp\htdocs\seeding-data-in-the-testing\tests\Feature\UserTest.php:25 2) Tests\Feature\UserTest::test_unfollowsError: Call to a member function unfollows() on null C:\xampp\htdocs\seeding-data-in-the-testing\tests\Feature\UserTest.php:35 3) Tests\Feature\UserTest::test_A_follows_B_and_CError: Call to a member function follows() on null C:\xampp\htdocs\seeding-data-in-the-testing\tests\Feature\UserTest.php:50 ERRORS!Tests: 6, Assertions: 3, Errors: 3.
不好。迁移正在工作,但数据播种没有在 DatabaseMigrations 上调用。
没关系;让我们尝试一下 DatabaseTransactions。
# tests/Feature/UserTest.phpclass UserTest extends TestCase{ use DatabaseTransactions; ...}
再次运行测试。
vendor\bin\phpunitPHPUnit 5.7.17 by Sebastian Bergmann and contributors. ...... 6 / 6 (100%) Time: 7.29 seconds, Memory: 14.00MB OK (6 tests, 6 assertions)
一切都很好!DatabaseTransactions Trait 将每个测试的查询包装在一个事务中,因此来自先前测试的数据不会干扰后续测试。
结论
使用计划的测试数据播种您的数据库可以模拟许多不同的情况,并毫不费力地加载大量数据。
少即是多。用更少的努力获得更好的结果。
您可以使用来自 这里 的示例项目。