2023-12-18|閱讀時間 ‧ 約 36 分鐘

PHPUnit 自動化測試大作戰【CH08】

前置: Factory & UserRepository

在開始實作資料庫測試之前,先與大家介紹 Factory 這個東西。

Factory 是個 Laravel 的 ORM:Eloquent 提供的功能,它可以讓我們用很簡單的方式,去準備測試資料,在 Laravel 初始化後,預設已經幫我們準備好了一個 UserFactory (而之所以 Laravel 官方預先準備了這個 Factory,可能是因為最基本預設的資料表,就是 users),慣例上會將 Factory 檔放在 database/factories這個資料夾下,並且會命名為 XxxFactory ,其中 Xxx 是資源名稱:

  • database/factories/UserFactory.php
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

use Illuminate\Support\Str;

/** * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User> */

class UserFactory extends Factory{

/** * Define the model's default state. * * @return array<string, mixed> */

public function definition() {

return [

'name' => fake()->name(),

'email' => fake()->unique()->safeEmail(),

'email_verified_at' => now(),

'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password

'remember_token' => Str::random(10),

]; } /** * Indicate that the model's email address should be unverified. * * @return static */

public function unverified() {

return $this->state(fn (array $attributes) => [

'email_verified_at' => null,

]); }}

Factory 有2種主要的使用方式,第1種是會在資料表實際建立資料,並且回應 Eloquent Enity,用法如下:

$user = User::facotry()->create();

以上程式碼會立即在資料庫建立 User資料,其中 nameemail 會使用 fake() 來隨機建立假值,email_verified_at 會用當下時間,remember_token 則會是一個隨機產生的 10 個字的字串。

另1種方式,則不會在資料庫建立資料,但仍會回應 Eloquent Enity,用法如下:

$user = User::facotry()->make();

不過要注意,用 make() 來建立資料實體,其 id 欄位值會是空值喔(因為沒有實際在資料庫建立資料)。

此外,也可以在建立資料時,指定你想要的欄位值:

$user = User::facotry()->create(['name' => 'william']);

以上就是 Factory 的相關介紹,當然其實還有更多有趣的技術細節值得探討,像是神秘的 fake() ,不過這讓我們在之後的文章再來探討吧!

理解了準備資料的方式後,讓我們來看看今天要測試的對象,以下是針對 User 這個資源,所實作的資料操作類別 UserRepository

  • app/Repositories/UserRepository.php
<?php

namespace App\Repositories;

use App\Models\User;

class UserRepository{

protected $model;

public function __construct(User $model) {

$this->model = $model;

} // 依給予的輸入資料,於資料庫中建立 User 資料

public function createUser(array $data) {

return $this->model::create($data);

} // 更新指定 ID 之 User 資料之姓名值

public function updateUserNameById($userId, string $name) {

$user = $this->getUserById($userId);

if (empty($user)) {

return false;

} $user->name = $name;

return $user->save();

} // 刪除指定 ID 之 User 資料

public function deleteUserById($userId) {

$user = $this->getUserById($userId);

if (empty($user)) {

return false;

} return $user->delete();

} // 讀取指定 ID 之 User 資料

public function getUserById($userId) {

return $this->model::find($userId);

}}

以上程式碼實作了關於 User 這個資源的 CRUD 4種操作,接著就來寫測試吧!

資料操作測試:建立

首先是建立資料功能的測試,請看以下程式碼:

namespace Tests\Feature;

use App\Repositories\UserRepository;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class UserRepositoryTest extends TestCase{

use RefreshDatabase;

/** * Example for user creating * @return void */

public function testUserCreating() {

$repository = app(UserRepository::class);

$repository->createUser([

'name' => 'test_name',

'email' => 'test@test.test',

'password' => 'password',

]); $this->assertDatabaseHas('users', [

'name' => 'test_name',

'email' => 'test@test.test',

'password' => 'password',

]); }}

以上程式碼,會呼叫 createUser() ,並在呼叫之後,驗證資料庫中是否存有期望中的資料。

資料操作測試:讀取

namespace Tests\Feature;

use App\Repositories\UserRepository;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class UserRepositoryTest extends TestCase{

use RefreshDatabase;

/** * Example for user reading * @return void */

public function testUserReading() {

$user = User::factory()->create();

$repository = app(UserRepository::class);

$userGot = $repository->getUserById($user->id);

$this->assertEquals($user->id, $userGot->id);

}}

以上程式碼,會先建立假資料 $user ,之後呼叫 getUserById() ,並在呼叫之後,驗證取得的資料之 ID 是否如預期。

資料操作測試:更新

namespace Tests\Feature;

use App\Repositories\UserRepository;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class UserRepositoryTest extends TestCase{

use RefreshDatabase;

/** * Example for user updating * @return void */

public function testUserUpdating() {

$user = User::factory()->create([

'name' => 'test_name',

'email' => 'test@test.test',

'password' => 'password',

]); $repository = app(UserRepository::class);

$repository->updateUserNameById($user->id, 'name_2');

$this->assertDatabaseHas('users', [

'name' => 'name_2',

]); }}

以上程式碼,會先建立假資料 $user ,之後呼叫 updateUserNameById() ,並在呼叫之後,驗證資料是否如期更新。

資料操作測試:刪除

namespace Tests\Feature;

use App\Repositories\UserRepository;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class UserRepositoryTest extends TestCase{

use RefreshDatabase;

/** * Example for user deletion * @return void */

public function testUserDeletion() {

$user = User::factory()->create([

'name' => 'test_name',

'email' => 'test@test.test',

'password' => 'password',

]); $userId = $user->id;

$repository = app(UserRepository::class);

$repository->deleteUserById($user->id);

$this->assertDatabaseMissing('users', [

'id' => $userId,

]); }}

以上程式碼,會先建立假資料 $user ,之後呼叫 deleteUseryId() ,並在呼叫之後,驗證資料是否如預期地刪除。

以上就是今天的資料庫測試介紹。

下一篇來為大家介紹與自動化測試相關的 Traits。

如果您喜歡這篇文章,歡迎加入追蹤以接收新文章通知 😄

參考資料

本系列文章目錄

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.