برنامه نویسی

تست نویسی در لاراول (Laravel) چیست + مثال کاربردی

از زمانی که تست نویسی به عنوان یک بخش جدایی ناپذیر از توسعه‌ی اپلیکیشن شناخته شد، زمان زیادی نمی‌گذرد تا تغییرات لازم در کدها صورت بگیرد. در واقع، تست‌ها برای این منظور طراحی شده‌اند که با اطمینان، می‌توانید کدهای قبلی را تغییر دهید. استفاده از تست، نه تنها این اعتماد به نفس را در توسعه دهنده ایجاد می‌کند، بلکه مهارت‌های برنامه نویسی او نیز افزایش می‌یابد.

با این حال، آمارها نشان می‌دهند که کمتر از یک چهارم اپلیکیشن‌های لاراول موجود، تست شده‌اند. این نکته نشان دهنده اهمیت روزافزونی است که تست نویسی برای توسعه‌ی اپلیکیشن دارد. با این حال، دلیل عمده‌ی این آمار پایین، معمولاً نداشتن دانش کافی در زمینه تست نویسی است که باعث می‌شود توسعه دهندگان لاراول نتوانند به راحتی و به صورت صحیح تست نویسی را در اپلیکیشن خود شروع کنند.

در این مقاله قصد داریم پاسخ این پرسش را بررسی کنیم و به دوستداران لاراول آموزش دهیم که چگونه و از کجا می‌توانند تست نویسی را در اپلیکیشن خود شروع کنند. لذا، پیشنهاد می‌کنیم تا انتهای مقاله‌ی Http Tests در لاراول با ما همراه باشید.

شروع به تست نویسی برای لاراول

برای شروع تست نویسی در لاراول، می‌توانید با یک درخواست Http ساده شروع کنید که یک پاسخ بسیار ساده را برمی‌گرداند. به عنوان یک توسعه دهنده‌ی لاراول، شاید به دنبال این باشید که از بخش‌های پیچیده‌ی اپلیکیشن خود برای تست نویسی شروع کنید؛ اما این احتمال دارد که به زودی از تست نویسی خسته شده و آن را در نیمه‌ی راه رها کنید. بهتر است به یاد داشته باشید که تست نویسی باید یک فرآیند قدم به قدم، از قدم‌های کوچک‌تر به قدم‌های بزرگ‌تر باشد.

برای شروع آموزش Http Testing در لاراول، شما نیازمند دانش کافی در زمینه‌ی لاراول هستید. در این مقاله، قصد داریم بخش ثبت نام و احراز هویت پروژه‌ی لاراول خود را ایجاد کرده و با استفاده از Http Tests، آن را تست کنیم.

جهت نصب پروژه، ابتدا باید یک پروژه‌ی جدید لاراول را ایجاد نمایید. برای این منظور، می‌توانید با استفاده از دستور زیر، در مسیر دلخواه خود پروژه‌ی جدید را ایجاد کنید:

composer create-project --prefer-dist laravel/laravel testing-laravel

سپس با استفاده از دستور زیر، وارد پوشه‌ی پروژه‌ی ایجاد شده می‌شوید:

cd testing-laravel

سپس با استفاده از دستور زیر، سرور لوکال هاست را اجرا می‌کنید:

php artisan serve

با اجرای این دستور، پروژه بر روی پورت ۸۰۰۰ لوکال هاست در دسترس قرار می‌گیرد. با وارد کردن آدرس https://localhost:8000 در نوار آدرس مرورگر، با این صفحه مواجه می‌شوید:

در گام بعد، باید ارتباط با دیتابیس برقرار شود. برای این کار، در ابتدا باید یک دیتابیس مورد نظر ایجاد شود و سپس مقادیر متغیرهای زیر را در فایل env پروژه به‌روز کنید:

DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

در مرحله بعد، می‌توان با استفاده از دستور زیر، جداول مورد نیاز برای پروژه را در دیتابیس ایجاد کرد:

php artisan migrate

حالا وقت آن رسیده است که مسیرهای لازم برای پروژه‌ی خود را تعریف کنید. برای این منظور، به پوشه‌ی routes و فایل web.php مراجعه کرده و سپس سه مسیر زیر را برای احراز هویت و ثبت نام کاربران تعریف نمایید:

<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
    return view('welcome');
})->name('index');
Route::get('/login', [\App\Http\Controllers\AuthController::class, 'login'])->name('login');
Route::post('/login', [\App\Http\Controllers\AuthController::class, 'doLogin'])->name('doLogin');
Route::get('/register', [\App\Http\Controllers\AuthController::class, 'register'])->name('register');
Route::post('/register', [\App\Http\Controllers\AuthController::class, 'doRegister'])->name('doRegister');

ایجاد View در لاراول

برای ایجاد یک صفحه ورود کاربران در لاراول، شما می‌توانید به روش زیر عمل کنید:

  1. ابتدا با دستور زیر یک فایل جدید برای ویو صفحه ورود ایجاد کنید:
php artisan make:view auth.login
  1. سپس درون فایل ساخته شده (resources/views/auth/login.blade.php) کد HTML صفحه ورود را قرار دهید. به طور مثال:
@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Login') }}</div>

                    <div class="card-body">
                        <form method="POST" action="{{ route('login') }}">
                            @csrf

                            <div class="form-group row">
                                <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

                                    @error('email')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">

                                    @error('password')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group row">
                                <div class="col-md-6 offset-md-4">
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                        <label class="form-check-label" for="remember">
                                            {{ __('Remember Me') }}
                                        </label>
                                    </div>
                                </div>
                            </div>

                            <div class="form-group row mb-0">
                                <div class="col-md-8 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        {{ __('Login') }}
                                    </button>

                                    @if (Route::has('password.request'))
                                        <a class="btn btn-link" href="{{ route('password.request') }}">
                                            {{ __('Forgot Your Password?') }}
                                        </a>
                                    @endif
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection
  1. در نهایت، شما می‌توانید این ویو را در روتر (routes/web.php) به عنوان مسیر /login تعریف کنید:
Route::get('/login', function () {
    return view('auth.login');
})->name('login');

حال با باز کردن مرورگر و نوشتن آدرس http://localhost/login، صفحه ورود به سیستم شما را مشاهده خواهید کرد.

کدهای CSS پروزه

در مسیر public/css یک فایل CSS با نام style.css ایجاد کنید و کدهای زیر را در آن کپی کنید:

body {
    margin: 0;
    padding: 0;
    background-color: #17a2b8;
    height: 100vh;
}
#login .container #login-row #login-column #login-box {
    margin: 50px auto;
    max-width: 600px;
    height: auto;
    border: 1px solid #9C9C9C;
    background-color: #EAEAEA;
}
#login .container #login-row #login-column #login-box #login-form {
    padding: 20px;
}
#login .container #login-row #login-column #login-box #login-form #register-link {
    margin-top: -85px;
}

ایجاد کنترلر صفحه ورود در لاراول

برای ایجاد کنترلر صفحه ورود، شما می‌توانید از دستور زیر استفاده کنید:

php artisan make:controller AuthController

سپس در فایل راه‌اندازی کنترلر جدید (AuthController)، متدهای لازم برای نمایش صفحه ورود (login) و پردازش فرم ورود (authenticate) را تعریف کنید. به طور مثال:

namespace App\Http\Controllers;

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

class AuthController extends Controller
{
    public function showLoginForm()
    {
        return view('auth.login');
    }

    public function authenticate(Request $request)
    {
        $credentials = $request->only('email', 'password');

        if (Auth::attempt($credentials)) {
            // Authentication passed...
            return redirect()->intended('/');
        } else {
            return redirect()->back()->withErrors(['email' => 'These credentials do not match our records.']);
        }
    }
}

در این کد، showLoginForm برای نمایش صفحه ورود به سیستم و authenticate برای پردازش فرم ورود به سیستم استفاده می‌شود. همچنین، در صورت موفقیت‌آمیز بودن ورود به سیستم، کاربر به صفحه اصلی منتقل می‌شود و در غیر این صورت به صفحه‌ی قبل و خطای مربوط به ورود ناموفق نمایش داده می‌شود.

سپس برای تعریف مسیر وصول به کنترلر، کد زیر را در فایل routes/web.php اضافه کنید:

Route::get('/login', 'AuthController@showLoginForm')->name('login');
Route::post('/login', 'AuthController@authenticate');

در این کد، مسیر /login برای نمایش صفحه ورود به سیستم (showLoginForm) تعریف شده است. همچنین، برای پردازش فرم ورود به سیستم (authenticate) از مسیر پیش‌فرض POST برای فرستادن فرم استفاده شده است.

اجرای تست با PHPUnit در لاراول

در لاراول برای اجرای تست‌ها، از PHPUnit استفاده می‌شود که به صورت پیش‌فرض در فایل composer.json نصب شده است. برای اجرای تست‌ها در لاراول، می‌توانید از دستور زیر استفاده کنید:

php artisan test

این دستور، تمامی تست‌های موجود در پروژه را اجرا می‌کند و نتایج آن‌ها را نمایش می‌دهد.

همچنین، شما می‌توانید تست‌های خاصی را با استفاده از نام فایل یا نام تست مشخص کنید. به عنوان مثال، برای اجرای تست‌های موجود در فایل ExampleTest.php، می‌توانید از دستور زیر استفاده کنید:

php artisan test --filter ExampleTest

اگر شما تغییراتی در تنظیمات تست‌ها اعمال کرده‌اید، می‌توانید آن‌ها را در فایل phpunit.xml تعیین کنید.

همچنین، با اجرای تست‌ها، لاراول می‌تواند یک پایگاه داده آزمایشی را ایجاد کند تا در آن تست‌های شما اجرا شود. برای این منظور، لاراول از پایگاه داده SQLite استفاده می‌کند.

انواع تست‌ در لاراول

در لاراول، شما می‌توانید از انواع مختلف تست‌ها برای آزمون کردن برنامه‌ی خود استفاده کنید، این انواع تست به شرح زیر هستند:

  1. تست واحد (Unit Test):
    در این نوع تست، بخشی از کد بررسی می‌شود تا اطمینان حاصل شود که بخش‌های مختلف کد به درستی عمل می‌کنند. این تست‌ها بدون توجه به سایر قسمت‌های برنامه اجرا می‌شوند.
  2. تست شبه‌واقعی (Feature Test):
    در این نوع تست، واحد‌های جدید با واحدهای موجود در برنامه ترکیب می‌شوند و عملکرد کلی برنامه بررسی می‌شود. در این نوع تست، فرض بر این است که برنامه به درستی ساخته‌شده است و تست‌ها برای بررسی عملکرد صحیح برنامه هستند.
  3. تست واقعی (Browser Test):
    این نوع تست مانند تست شبه‌واقعی است، با این تفاوت که در این تست، بخش‌های مختلفی از برنامه از جمله واحدهای سمت کاربر (Front End) و برخی بخش‌های Back-End بررسی می‌شوند. به طور مثال، در این نوع تست می‌توانید کلیک روی دکمه‌ی خاصی را به عنوان یک خطا در صورت وجود مشکل تشخیص دهید.
  4. تست API:
    در این نوع تست، برنامه به عنوان یک API بررسی می‌شود. به طور مثال، در این نوع تست می‌توانید تماس با API خاصی را بررسی کنید و بررسی کنید که آیا درخواست‌ها به درستی پاسخ داده می‌شوند یا خیر.

همچنین، لاراول از چارچوب PHPUnit برای اجرای تست‌ها استفاده می‌کند. در این چارچوب، شما می‌توانید از توابعی مانند assertTrue، assertEquals و … برای اطمینان حاصل کردن از صحت اجرای برنامه در زمان تست استفاده کنید.

چگونگی ساماندهی تست‌ها در لاراول

در لاراول، برای ساماندهی بهتر تست‌ها و کاهش پیچیدگی در اجرای آن‌ها، می‌توانید از چندین روش استفاده کنید. این روش‌ها عبارتند از:

  1. دسته‌بندی تست‌ها:
    شما می‌توانید تست‌های خود را براساس عملکرد یا قسمت‌های مختلف برنامه‌ی خود دسته‌بندی کنید. به عنوان مثال، می‌توانید تست‌هایی را برای بخش Front-End و تست‌هایی دیگر را برای بخش Back-End دسته‌بندی کنید.
  2. فایل‌های جداگانه برای تست:
    شما می‌توانید فایل‌های جداگانه‌ای برای تست‌های خود ایجاد کنید تا از پیچیدگی کد کم‌تری برخوردار باشید. به عنوان مثال، می‌توانید برای هر مدل در برنامه‌ی خود یک فایل تست جداگانه‌ای ایجاد کنید.
  3. تست‌های اتوماتیک:
    شما می‌توانید تست‌های خود را به صورت اتوماتیک اجرا کنید تا در هر بار تغییر کد، تست‌های شما نیز اجرا و بررسی شوند. این روش برای جلوگیری از خطا در اجرای برنامه و تضمین صحت عملکرد برنامه بسیار مفید است.
  4. Mocking:
    با استفاده از Mocking، شما می‌توانید تست‌های خود را به راحتی ایجاد کنید. به عنوان مثال، اگر یک متد دارای وابستگی به یک کلاس دیگر باشد، شما می‌توانید از Mocking استفاده کنید تا ابتدا یک کلاس جعلی برای تست‌های خود ایجاد کنید و سپس این کلاس را به متد خود ارسال کنید.

همچنین، در لاراول شما می‌توانید تست‌های خود را در پوشه‌ی tests قرار دهید و از فضای نام PHPUnit برای اجرای تست‌ها استفاده کنید.

در کل، با ساماندهی مناسب تست‌ها و استفاده از روش‌های مناسب برای ایجاد و اجرای آن‌ها، می‌توانید به صورت موثرتر و کارآمدتر تست‌های خود را پیاده‌سازی کنید.

تست‌های کاربردی در لاراول

تست شماره یک

برای تست اول میخواهیم وقتی که یک درخواست GET را به مسیر login ارسال می‌کنیم، فایل View باید با نام auth.login به ما نشان داده شود.

برای نوشتن تست مورد نظر، می‌توانید از فایل TestCase پیشفرض لاراول استفاده کنید و در آن یک تابع با نام test_login_view را تعریف کنید. سپس با استفاده از تابع get موجود در این کلاس، درخواست GET به مسیر login ارسال کرده و با استفاده از تابع assertViewIs موجود در Laravel، مطمئن شوید که فایل auth.login بارگذاری شده است. کد مورد نیاز برای این تست به صورت زیر است:

use Illuminate\Foundation\Testing\TestCase;

class LoginTest extends TestCase
{
    public function test_login_view()
    {
        $response = $this->get('/login');
        $response->assertViewIs('auth.login');
    }
}

این تست درخواست GET را به مسیر /login ارسال می‌کند و سپس مطمئن می‌شود که فایل auth.login با موفقیت بارگذاری شده است.

تست شماره دو

در تست دوم میخواهیم که وقتی که یک درخواست POST را با اطلاعات نادرست به آدرس /login ارسال می‌کنیم، باید به صفحه‌ی ورود Redirect شویم و یک اخطار اعتبارسنجی یا Validation Error دریافت کنیم.

برای نوشتن تست مورد نظر، می‌توانید از فایل TestCase پیشفرض لاراول استفاده کنید و در آن یک تابع با نام test_login_with_invalid_data را تعریف کنید. سپس با استفاده از تابع post موجود در این کلاس، درخواست POST به مسیر login با داده‌های نادرست ارسال کنید و با استفاده از تابع assertRedirect و expectValidationError موجود در Laravel، مطمئن شوید که به صفحه‌ی ورود Redirect شده‌اید و خطاهای اعتبارسنجی (Validation Error) دریافت کرده‌اید. کد مورد نیاز برای این تست به صورت زیر است:

use Illuminate\Foundation\Testing\TestCase;

class LoginTest extends TestCase
{
    public function test_login_with_invalid_data()
    {
        $response = $this->post('/login', [
            'email' => 'invalid-email',
            'password' => ''
        ]);

        $response->assertRedirect('/login');
        $response->expectValidationError();
    }
}

در این تست، ابتدا یک درخواست POST با داده‌های نادرست به مسیر /login ارسال می‌شود. سپس با استفاده از تابع assertRedirect مطمئن می‌شویم که به صفحه‌ی ورود Redirect شده‌ایم. در نهایت با استفاده از تابع expectValidationError مطمئن می‌شویم که خطاهای اعتبارسنجی (Validation Error) دریافت کرده‌ایم.

تست شماره سه: ورود موفقیت آمیز کاربر

برای نوشتن تست مربوط به ورود موفق کاربر در لاراول، می‌توانید از فایل TestCase پیشفرض استفاده کنید و در آن یک تابع با نام test_login_successfully را تعریف کنید. سپس با استفاده از تابع post موجود در این کلاس، درخواست POST به مسیر login با داده‌های صحیح ارسال کرده و با استفاده از تابع assertRedirect موجود در Laravel، مطمئن شوید که با ورود موفقیت‌آمیز به حساب کاربری، به مسیری Redirect شده‌اید که در تنظیمات مشخص شده است. کد مورد نیاز برای این تست به صورت زیر است:

use Illuminate\Foundation\Testing\TestCase;
use App\Models\User;

class LoginTest extends TestCase
{
    public function test_login_successfully()
    {
        // Create a user for testing purposes
        $user = User::factory()->create([
            'email' => '[email protected]',
            'password' => bcrypt('password')
        ]);

        $response = $this->post('/login', [
            'email' => '[email protected]',
            'password' => 'password'
        ]);

        $response->assertRedirect('/home');
    }
}

در این تست، ابتدا یک کاربر برای تست‌ها ایجاد شده است. سپس با استفاده از تابع post، درخواست POST به مسیر /login با داده‌های صحیح ارسال می‌شود. در نهایت با استفاده از تابع assertRedirect مطمئن می‌شویم که با ورود موفقیت‌آمیز به حساب کاربری، به مسیری Redirect شده‌اید که در تنظیمات مشخص شده است.

تست شماره چهار: ثبت نام موفق کاربران

برای نوشتن تست مربوط به ثبت نام موفق کاربر در لاراول، می‌توانید از فایل TestCase پیشفرض استفاده کنید و در آن یک تابع با نام test_register_successfully را تعریف کنید. سپس با استفاده از تابع post موجود در این کلاس، درخواست POST به مسیر register با داده‌های صحیح ارسال کرده و با استفاده از تابع assertRedirect موجود در Laravel، مطمئن شوید که با ثبت نام موفقیت‌آمیز، به مسیری Redirect شده‌اید که در تنظیمات مشخص شده است. همچنین می‌توانید با استفاده از تابع assertDatabaseHas موجود در Laravel، مطمئن شوید که اطلاعات کاربری با مشخصات درست در جدول users در دیتابیس ذخیره شده است. کد مورد نیاز برای این تست به صورت زیر است:

use Illuminate\Foundation\Testing\TestCase;
use App\Models\User;

class RegisterTest extends TestCase
{
    public function test_register_successfully()
    {
        $response = $this->post('/register', [
            'name' => 'John Doe',
            'email' => '[email protected]',
            'password' => 'password',
            'password_confirmation' => 'password'
        ]);

        $response->assertRedirect('/home');
        $this->assertDatabaseHas('users', [
            'name' => 'John Doe',
            'email' => '[email protected]'
        ]);
    }
}

در این تست، با استفاده از تابع post، درخواست POST به مسیر /register با داده‌های صحیح ارسال می‌شود. سپس با استفاده از تابع assertRedirect مطمئن می‌شویم که با ثبت نام موفقیت‌آمیز، به مسیری Redirect شده‌اید که در تنظیمات مشخص شده است. همچنین با استفاده از تابع assertDatabaseHas، مطمئن می‌شویم که اطلاعات کاربری با مشخصات درست در جدول users در دیتابیس ذخیره شده است.

تست شماره پنج: ثبت نام موفق کاربران

برای تست مسیرهایی که نیاز به احراز هویت دارند در لاراول، می‌توانید از دو روش استفاده کنید:

  1. استفاده از trait Authenticated و تعریف یک کلاس پایه برای تست کردن مسیرهایی که نیاز به احراز هویت دارند:
use Illuminate\Foundation\Testing\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Auth\User as Authenticatable;

class AuthenticatedTestCase extends TestCase
{
    use DatabaseMigrations, RefreshDatabase;

    protected $user;

    protected function setUp(): void
    {
        parent::setUp();

        $this->user = factory(Authenticatable::class)->create();
        $this->actingAs($this->user);
    }
}

در این کلاس، از تریت Authenticated برای ایجاد یک کاربر و ورود به سیستم استفاده شده است. همچنین با ارث‌بری از کلاس TestCase، از تریت RefreshDatabase برای پاک کردن دیتابیس در پایان هر تست استفاده شده است.

  1. استفاده از تابع actingAs برای ورود به سیستم در هر تست:
public function test_authenticated_route()
{
    $user = factory(User::class)->create();

    $response = $this->actingAs($user)
                     ->get('/authenticated-route');

    $response->assertStatus(200);
}

در این تست، با استفاده از تابع actingAs، کاربر ورودی به سیستم وارد شده و سپس با استفاده از تابع get، درخواست GET به مسیر /authenticated-route ارسال می‌شود. سپس با استفاده از تابع assertStatus، مطمئن می‌شویم که درخواست با موفقیت پاسخ داده شده است.

جمع بندی پایانی:

در بخش‌هایی از اپلیکیشن که مانند ورود ناموفق، با تست‌های مختلف می‌توانید تمامی ارورها را شبیه‌سازی و تست کنید. اما هدف تست نویسی، اطمینان از صحت اجرای کدها و روند کلی اپلیکیشن است. به همین دلیل در این موارد، سعی کنید یک حالت را از تمامی حالات در نظر بگیرید و با اجرای موفقیت‌آمیز تست مربوطه، اطمینان حاصل کنید که اپلیکیشن شما در صورت بروز خطا، به درستی عمل خواهد کرد.

در مقاله Http Tests در لاراول که به عنوان یکی از مجموعه مقالات آموزشی لاراول منتشر شده است، با استفاده از روش TDD یا Test Driven Development، بخش احراز هویت و ثبت نام اپلیکیشن خود را ایجاد کرده و تست‌های مربوطه را تعریف کردیم. این روش تست نویسی به عنوان Http Test شناخته می‌شود و درواقع درخواست‌های Http و پاسخ‌های برگشتی را در اپلیکیشن لاراول، شبیه‌سازی می‌کند. شما هم می‌توانید با استفاده از این روش، برای اپلیکیشن‌های خود، تست نویسی را انجام داده و در نهایت از صحت عملکرد کدهای خود در حالت بهره‌برداری، اطمینان حاصل کنید.

ما امیدواریم که مقاله Http Tests در لاراول، برای شما مفید واقع شده باشد و خوشحال می‌شویم اگر تجربیات، سوالات و نظرات خود را با ما و سایر کاربران سون لرن به اشتراک بگذارید.

همچنین اگر به یادگیری لاراول علاقه مند هستید توصیه میکنیم مقاله: ۶ کانال برتر برای یادگیری لاراول (Laravel) را در بایت گیت از دست ندهید.

پوریا گودرز

پوریا گودرز هستم‌ علاقه مند به مباحث‌ و‌‌ مشکلات مربوط به تکنولوژی و فناوری. همچنین اندک آشنایی در زمینه گرافیک دارم. امیدوارم بتونم مشکلات شما رو در این مباحث حل کنم . انتقادات خود را از بخش نظرات با من در میان بگذارید :)

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *