System

Laravel Unit Test & Feature Test

မင်္ဂလာပါ။
ကျွန်တော်ကတော့ Spiceworks Myanmar မှာ Backend Developer အနေနဲ့ တာဝန်ယူလုပ်ကိုင်နေတဲ့ သုတယာမိုး ဖြစ်ပါတယ်။ အခု blog မှာတော့ Laravel Unit Test နှင့် Feature Test အကြောင်းကို ဝေမျှပေးသွားမှာဖြစ်ပါတယ်။

What is Testing?

Testing ဆိုတာကတော့ ကျွန်တော်တို့ရဲ့ လုပ်ဆောင်ချက်တွေက သတ်မှတ်ထားတဲ့ လိုအပ်ချက်များနှင့် ကိုက်ညီမှုရှိလား၊ မရှိဘူးလား အကဲဖြတ်တဲ့ လုပ်ငန်းစဥ်တစ်ခုဖြစ်ပါတယ်။ နည်းပညာပိုင်းမှာ ဆိုရင်တော့ ကျွန်တော်တို့ရေးထားတဲ့ ကုဒ်တွေက စနစ်ကျလား၊ မှန်ကန်မှုရှိလား၊ ပြောင်းလဲရလွယ်လား စသဖြင့် အကဲဖြတ်တဲ့အခါ အသုံးပြုကြပါတယ်။

TYPES OF TESTS IN LARAVEL

Laravel မှာကတော့ ထိုသို့စမ်းသပ်မှုတွေကို ပြုလုပ်နိုင်ဖို့အတွက် Unit Test နှင့် Feature Test ဟူ၍ နည်းလမ်းနှစ်မျိုး built-in ပါဝင်ပါတယ်။ Testing လုပ်ဖို့အတွက် phpunit.xml file မှာ မိမိ testing အတွက် အသုံးပြုမယ့် database connection နှင့် database name ကို ပြောင်းလဲပေးဖို့လိုအပ်ပါတယ်။

<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>

Unit Test

Unit Test မှာတော့ database ချိတ်ဆက်မှုတွေ၊ http request တွေမပါဝင်ဘဲ method တစ်ခု၊ class တစ်ခု အစရှိသဖြင့် သီခြား အစိတ်အပိုင်းတစ်ခုတည်းကိုပဲ အထူးပြုပြီး testing လုပ်ချင်တဲ့အခါမှာ အသုံးပြုပါတယ်။ Laravel Unit Test တစ်ခု တည်ဆောက်ဖို့ အတွက် အောက်ပါ command ကို အသုံးပြုပေးပါ။

php artisan make:test UserTest --unit

ထို့နောက် /tests/Unit/UserTest.php မှာ params_are_not_nullable ဆိုတဲ့ test case တစ်ခုရေးကြည့်ပါမယ်။ နောက်ပြီးတော့ ထို test case ကို စမ်းဖို့အတွက် calculate ဆိုပြီး class တစ်ခု create လုပ်ပါမယ်။ params_are_not_nullable မှာကတော့ Calculate class ထဲက add() method ကိုပေးပို့လိုက်တဲ့ parameters တွေက null မဖြစ်ရဘူးဆိုတဲ့ စမ်းသပ်ချက်ဖြစ်ပါတယ်။

#app/Services/calculate.php
<?php

namespace App\Services;

class Calculate {
    public function add($a = null, $b = null) {
        if ($a === null || $b === null) {
            throw new \InvalidArgumentException('Please provide two numbers to add.');
        }
        return $a + $b;
    }
}

#tests/Unit/UserTest.php
expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage('Please provide two numbers to add.');

        $calculate = new Calculate();
        $calculate->add();
    }
}

ထို test_case ကို စမ်းသပ်ဖို့အတွက် အောက်ပါ command ကို အသုံးပြုပေးပါ။

php artisan test --filter:UnitTest::test_params_cannot_be_null

Feature Test

Login Feature တစ်ခုရှိတယ်ဆိုပါစို့။ User ကနေ ပေးပို့လိုက်တဲ့ data တွေက valid ဖြစ်ရမယ်၊ user ကနေ ပေးပို့လိုက်တဲ့ api request headers တွေက မှန်ကန်မှုရှိရမယ်၊ login api ကို unauthenticated user ကပဲ ဝင်ခွင့်ရရမယ်၊ ထို့နောက် login လုပ်ဆောင်ချက်အောင်မြင်ပြီးတဲ့အခါ user ဘက်သို့ပြန်လည်ပေးပို့လိုက်တဲ့ data တွေက သတ်မှတ်ထားတာနှင့် ကိုက်ညီရမယ် အစရှိသဖြင့် feature တစ်ခုလုံးကို စမ်းသပ်လိုတဲ့အခါ Feature Test ကို အသုံးပြုပါတယ်။ Laravel Feature Test တစ်ခု တည်ဆောက်ဖို့ အတွက် အောက်ပါ command ကို အသုံးပြုပေးပါ။

php artisan make:test UserTest

ထို့နောက် အထက်မှာဖော်ပြထားတဲ့ Login Feature ကိုစမ်းသပ်ဖို့အတွက် php artisan install:api command ကို run ပေးပြီး login route နှင့် authcontroller တို့ကို အောက်ပါအတိုင်းတည်ဆောက်ပေးပါ။

#routes/api.php
<?php

use App\Http\Controllers\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

Route::get('/login', [AuthController::class, 'login']);
#app/Http/Controllers/AuthController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
    public function login(Request $request) {
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        if (Auth::attempt(['email' => $request->email,'password' => $request->password])) {
            return response()->json([
                'user' => Auth::user(),
                'authToken' => Auth::user()->createToken('test_case')->plainTextToken,
            ], Response::HTTP_OK);
        } else {
            $response = ['error' => 'Email and password do not match.'];
            return response()->json($response, Response::HTTP_UNPROCESSABLE_ENTITY);
        }
    }
}

test_login_requires_email_and_password (email နှင့် password မထည့်ဘဲ 422 status code return ပြန်တာကိုစမ်းသပ်ခြင်း)၊ test_login_requires_valid_email (invalid email ထည့်ပြီး 422 status code return ပြန်တာကိုစမ်းသပ်ခြင်း)၊ test_login_succeeds_with_valid_credentials (email နှင့် password အမှန်ကိုထည့်ပြီး 200 status code return ပြန်တာကိုစမ်းသပ်ခြင်း) နှင့် test_json_structure (login အောင်မြင်ပြီး ပြန်လည်ပေးပို့လာတဲ့ json မှာ user နှင့် authToken ပါဝင်တာကို စမ်းသပ်ခြင်း) တို့ကို အောက်ပါအတိုင်း testing ပြုလုပ်နိုင်ပါတယ်။

#tests/Feature/UserTest.php
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    use RefreshDatabase, WithFaker;

    public function test_login_requires_email_and_password()
    {
        $response = $this->postJson('/api/login', []);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['email', 'password']);
    }

    public function test_login_requires_valid_email()
    {
        $response = $this->postJson('/api/login', [
            'email' => 'invalid-email',
            'password' => 'password'
        ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['email']);
    }

    public function test_login_succeeds_with_valid_credentials()
    {
        $user = User::factory()->create([
            'name' => 'John Doe',
            'email' => 'test@example.com',
            'password' => bcrypt('password')
        ]);

        $response = $this->postJson('/api/login', [
            'email' => $user->email,
            'password' => 'password'
        ]);

        $response->assertStatus(200);
    }

    public function test_json_structure()
    {
        $user = User::factory()->create([
            'name' => 'John Doe',
            'email' => 'test1@example.com',
            'password' => bcrypt('password')
        ]);

        $response = $this->postJson('/api/login', [
            'email' => $user->email,
            'password' => 'password'
        ]);

        $response->assertJsonStructure([
            'user' => [
                'id',
                'name',
                'email',
                'email_verified_at',
                'created_at',
                'updated_at'
            ],
            'authToken'
        ]);
    }
}

ထို test_case ကို စမ်းသပ်ဖို့အတွက် အောက်ပါ command ကို အသုံးပြုပေးပါ။

php artisan test --filter:UnitTest

အခုဆိုရင်တော့ Laravel Unit Test နှင့် Feature Test အကြောင်းကို နားလည်သွားမယ်လို့ ထင်ပါတယ်။ အဆုံးထိဖတ်ရှုပေးတဲ့အတွက် ကျေးဇူးတင်ပါတယ် ခင်ဗျ။

Hello

Leave a Reply

Your email address will not be published. Required fields are marked *