DEV Community

Cover image for Testing Laravel 13 dengan PHP 8.5 dan PHP 8.6 Menggunakan Incus
hardyweb
hardyweb

Posted on

Testing Laravel 13 dengan PHP 8.5 dan PHP 8.6 Menggunakan Incus

Dalam proses pembangunan sistem yang mengikuti kitaran SDLC, seperti KRISA, pengujian bukan hanya dilakukan pada penghujung pembangunan. Pengujian perlu dilaksanakan secara berterusan bagi memastikan sistem yang dibangunkan kekal serasi dengan perubahan pada persekitaran teknikalnya.

Salah satu perkara yang boleh diuji ialah keserasian antara interpreter atau runtime yang digunakan dengan software framework yang dibangunkan. Dalam konteks aplikasi Laravel, contohnya, kita boleh menguji aplikasi yang sama menggunakan versi PHP yang lebih baharu untuk melihat sama ada terdapat perubahan pada dependency, extension, API atau tingkah laku runtime yang memberi kesan kepada sistem.

Pendekatan ini membolehkan kita mengesan isu keserasian lebih awal dalam kitaran pembangunan, bukannya hanya selepas sesuatu versi PHP mula digunakan di production.

Dalam nota ini, Incus digunakan untuk menyediakan environment PHP yang berbeza supaya aplikasi Laravel yang sama boleh diuji secara berulang terhadap beberapa versi PHP.

WSL
└── Incus
    ├── laravel13-php85
    │   └── PHP 8.5
    │
    └── laravel13-php86
        └── PHP 8.6
Enter fullscreen mode Exit fullscreen mode

Tujuannya bukan untuk menjalankan dua project yang berbeza, tetapi untuk menguji codebase dan dependency yang sama pada runtime PHP yang berbeza.


Prinsip penting: gunakan composer.lock yang sama

Untuk compatibility testing, kita mahu kedua-dua environment menggunakan dependency yang sama.

Jadi jangan terus buat:

composer update
Enter fullscreen mode Exit fullscreen mode

dalam setiap container.

Sebaliknya gunakan:

composer install
Enter fullscreen mode Exit fullscreen mode

composer install akan menggunakan composer.lock yang sedia ada.

Contohnya:

                composer.lock
                     │
             ┌───────┴───────┐
             ▼               ▼
          PHP 8.5          PHP 8.6
             │               │
          test #1          test #2
Enter fullscreen mode Exit fullscreen mode

Dengan cara ini, perbezaan yang kita lihat lebih tertumpu kepada PHP runtime, bukan kerana Composer memilih versi dependency yang berbeza.


Flow 1 — Bind Mount

Ini ialah flow yang paling mudah untuk development dan testing harian.

Source code kekal di WSL:

/home/hardy/projects/laravel13
Enter fullscreen mode Exit fullscreen mode

Kemudian directory tersebut di-mount ke kedua-dua container.

Contoh:

incus config device add laravel13-php85 app disk \
    source=/home/hardy/projects/laravel13 \
    path=/var/www/html
Enter fullscreen mode Exit fullscreen mode

Dan:

incus config device add laravel13-php86 app disk \
    source=/home/hardy/projects/laravel13 \
    path=/var/www/html
Enter fullscreen mode Exit fullscreen mode

Sekarang kedua-dua container melihat source code yang sama.

WSL
└── projects/
    └── laravel13/
        ├── app/
        ├── config/
        ├── routes/
        ├── composer.json
        └── composer.lock
             │
             ├──────────────► PHP 8.5 container
             │
             └──────────────► PHP 8.6 container
Enter fullscreen mode Exit fullscreen mode

Install dependency

Masuk ke container PHP 8.5:

incus exec laravel13-php85 -- bash
Enter fullscreen mode Exit fullscreen mode

Kemudian:

cd /var/www/html

php -v
composer install
composer check-platform-reqs
Enter fullscreen mode Exit fullscreen mode

Run test:

php artisan test
Enter fullscreen mode Exit fullscreen mode

Kemudian ulangi pada PHP 8.6:

incus exec laravel13-php86 -- bash
Enter fullscreen mode Exit fullscreen mode
cd /var/www/html

php -v
composer install
composer check-platform-reqs
php artisan test
Enter fullscreen mode Exit fullscreen mode

Perkara yang perlu diperhatikan dengan bind mount

Bind mount sangat convenient, tetapi filesystem host dan container menjadi agak coupled.

Antara masalah yang mungkin muncul ialah UID/GID dan permission.

Dalam sesetengah setup Incus, kita mungkin menggunakan:

shift=true
Enter fullscreen mode Exit fullscreen mode

pada disk device.

Contohnya:

incus config device set laravel13-php85 app shift=true
Enter fullscreen mode Exit fullscreen mode

Tetapi ini bukan sesuatu yang perlu dijadikan default untuk flow kita.

shift=true boleh mempengaruhi bagaimana ownership file dipersembahkan antara host dan container. Untuk development workflow, kita lebih baik kekalkan setup mount yang simple dan hanya tackle UID/GID apabila memang diperlukan.

Jika selesai testing dan sebelum kembali kepada workflow biasa, kita boleh set:

incus config device set laravel13-php85 app shift=false
incus config device set laravel13-php86 app shift=false
Enter fullscreen mode Exit fullscreen mode

Flow 2 — Rsync atau Git

Untuk environment yang lebih clean, kita boleh elakkan bind mount.

Sebaliknya, source code disalin ke dalam filesystem container.

Contohnya menggunakan rsync:

WSL source
    │
    │ rsync
    ▼
Incus container
    │
    └── /var/www/html
Enter fullscreen mode Exit fullscreen mode

Contoh:

rsync -a --delete \
    --exclude vendor \
    --exclude node_modules \
    ./ /path/to/container/
Enter fullscreen mode Exit fullscreen mode

Atau kita boleh gunakan Git:

git clone <repository> /var/www/html
Enter fullscreen mode Exit fullscreen mode

Kemudian:

cd /var/www/html
composer install
Enter fullscreen mode Exit fullscreen mode

Penting: composer.lock masih digunakan

Rsync atau Git tidak bermaksud Composer akan ignore composer.lock.

Selagi file ini ada:

composer.json
composer.lock
Enter fullscreen mode Exit fullscreen mode

dan kita menjalankan:

composer install
Enter fullscreen mode Exit fullscreen mode

Composer akan menggunakan composer.lock.

Apa yang fresh ialah directory:

vendor/
Enter fullscreen mode Exit fullscreen mode

Contohnya:

Source repository
│
├── composer.json
├── composer.lock
├── app/
├── routes/
└── ...
        │
        │ rsync / git
        ▼
Container
│
├── composer.json
├── composer.lock
├── app/
├── routes/
└── ...
        │
        │ composer install
        ▼
    vendor/
Enter fullscreen mode Exit fullscreen mode

Jadi kita masih mendapat dependency versions yang sama.


Kenapa Flow 2 lebih clean?

Dengan Git atau rsync, container mempunyai filesystem sendiri.

Contohnya:

laravel13-php85
└── /var/www/html
    ├── app
    ├── config
    ├── composer.json
    ├── composer.lock
    └── vendor

laravel13-php86
└── /var/www/html
    ├── app
    ├── config
    ├── composer.json
    ├── composer.lock
    └── vendor
Enter fullscreen mode Exit fullscreen mode

Setiap environment mempunyai vendor/ sendiri.

Ini lebih dekat dengan situasi:

  • CI/CD
  • staging
  • deployment
  • production build
  • compatibility testing yang isolated

Cuma workflow menjadi sedikit lebih lambat kerana setiap perubahan source perlu di-sync atau checkout semula.


Mana satu digunakan?

Untuk kerja harian, saya akan gunakan Flow 1 — bind mount.

Sebabnya mudah:

Edit code
   ↓
WSL
   ↓
Container nampak perubahan terus
   ↓
Run test
Enter fullscreen mode Exit fullscreen mode

Ia sangat sesuai untuk exploratory testing.

Manakala Flow 2 lebih sesuai apabila kita mahu memastikan environment betul-betul isolated:

Git/Rsync
   ↓
Container
   ↓
composer install
   ↓
Test
Enter fullscreen mode Exit fullscreen mode

Checklist compatibility test

Untuk setiap versi PHP:

php -v
Enter fullscreen mode Exit fullscreen mode

Kemudian:

composer install
Enter fullscreen mode Exit fullscreen mode

Semak platform requirements:

composer check-platform-reqs
Enter fullscreen mode Exit fullscreen mode

Run Laravel test:

php artisan test
Enter fullscreen mode Exit fullscreen mode

Jika mahu periksa dependency yang menghalang PHP tertentu:

composer why-not php 8.6
Enter fullscreen mode Exit fullscreen mode

Untuk melihat apa yang akan berubah tanpa benar-benar update:

composer update --dry-run
Enter fullscreen mode Exit fullscreen mode

Tetapi command ini digunakan untuk mengkaji dependency resolution, bukan baseline compatibility test.


Contoh workflow

Katakan kita sedang berada pada PHP 8.5.

incus exec laravel13-php85 -- bash
Enter fullscreen mode Exit fullscreen mode
cd /var/www/html

php -v
composer install
composer check-platform-reqs
php artisan test
Enter fullscreen mode Exit fullscreen mode

Kemudian test PHP 8.6:

incus exec laravel13-php86 -- bash
Enter fullscreen mode Exit fullscreen mode
cd /var/www/html

php -v
composer install
composer check-platform-reqs
php artisan test
Enter fullscreen mode Exit fullscreen mode

Hasilnya boleh dibandingkan:

Laravel 13
│
├── PHP 8.5
│   ├── composer install    ✓
│   ├── platform reqs       ✓
│   └── tests               ✓
│
└── PHP 8.6
    ├── composer install    ✓
    ├── platform reqs       ✓
    └── tests               ✓
Enter fullscreen mode Exit fullscreen mode

Jika PHP 8.6 gagal, kita boleh isolate puncanya:

PHP runtime?
    │
    ├── Extension missing?
    │
    ├── Platform requirement?
    │
    ├── Composer dependency?
    │
    └── Application/test failure?
Enter fullscreen mode Exit fullscreen mode

Contohnya, error:

Class "Normalizer" not found
Enter fullscreen mode Exit fullscreen mode

boleh menunjukkan PHP intl extension belum tersedia.

Check:

php -m | grep -i intl
Enter fullscreen mode Exit fullscreen mode

Dan:

php -r 'var_dump(class_exists("Normalizer"));'
Enter fullscreen mode Exit fullscreen mode

Kesimpulan

Incus sesuai digunakan untuk membuat compatibility matrix yang kecil tanpa perlu Docker atau VM penuh.

Untuk development/testing cepat:

Bind mount
    ↓
PHP 8.5 / PHP 8.6
    ↓
composer install
    ↓
composer check-platform-reqs
    ↓
php artisan test
Enter fullscreen mode Exit fullscreen mode

Untuk environment yang lebih isolated:

Git / rsync
    ↓
Container filesystem
    ↓
composer install
    ↓
php artisan test
Enter fullscreen mode Exit fullscreen mode

Perkara paling penting ialah jangan ubah dependency set ketika membandingkan PHP versions.

Gunakan:

composer install
Enter fullscreen mode Exit fullscreen mode

dengan composer.lock yang sama.

Dengan itu kita boleh membezakan dengan lebih jelas sama ada sesuatu masalah datang daripada PHP version, PHP extension, dependency, atau memang daripada application code itu sendiri.

Top comments (0)