ถ้าต้องการศึกษา
Laravel framework ซึ่งเป็นสิ่งใหม่สำหรับผม
คำถามที่น่าสนใจก็คือ จะทำการศึกษา และ เรียนรู้ ฝึกทำอย่างไรดีล่ะ ?
คำตอบนั้นมีอยู่หลายแบบ
แต่สำหรับผมแล้ว ขอเริ่มจากการเขียน test หรือ ชุดการทดสอบดีกว่า !!
ดังนั้นมาเริ่มกันเลย
ปล. ไม่พูดถึงการสร้าง project และเตรียม environment นะครับ
มีเป้าหมายหลักเพื่อ
เรียนรู้การพัฒนาระบบด้วย Laravel framework
เรียนรู้โครงสร้างการทำงานพื้นฐานของ Laravel framework เช่น
- Factory
- Model ซึ่งมี ORM มาให้
- Database migration
- Routing
- Controller
- View
เริ่มด้วยการเขียนชุดการทดสอบในระดับ Acceptance Test
โดยสิ่งที่ต้องการคือ ขั้นตอนการสร้างบัญชีธนาคารของผู้ใช้งาน
ดังนั้นการทำงานมีขั้นตอนดังนี้
- สร้างผู้ใช้งาน
- สร้างบัญชีธนาคารใหม่
- ตรวจสอบผลการสร้างบัญชีใหม่ ว่าแสดงผลหมายเลขบัญชีใหม่ถูกต้องหรือไม่
สามารถเขียนชุดการทดสอบด้วย PHPUnit ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="testcase_01.php"]
ทำการทดสอบด้วยคำสั่ง
[code]
$./vendor/bin/phpunit
[/code]
ผลที่ได้แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่รู้จัก User ใน Factory !!!
แต่ประเด็นหลักคือ
Factory ของ Model คืออะไร ?
และมันอยู่ตรงไหนล่ะ ?
ตอบง่าย ๆ คือ โรงงานผลิต Model ไงล่ะ
ใครอยากจะจัดการข้อมูลผ่าน database ก็มาหาจากที่นี่ได้เลย
เมื่อลองไปค้นหาใน project พบว่าอยู่ในไฟล์ database/factories/ModelFactory.php นั่นเอง
แสดงดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="ModelFactory.php"]
จาก code ดังกล่าว
จะเห็นได้ว่าใน factory มี User อยู่แล้ว
แต่ว่า User มันอยู่ใน namspace ชื่อว่า App
ดังนั้นสิ่งที่เราควรทำคือ ในชุดการทดสอบ
ให้ทำการ import หรือ use App\User สิครับ ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="testcase_02.php"]
จากนั้นทำการทดสอบรอบที่สอง
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่สามารถติดต่อ MySQL database ได้ไง
แสดงว่า default database ของ Laravel framework คือ MySQL นั่นเอง
ได้ความรู้ใหม่กันอีกแล้ว
คำถามต่อมาคือ จะทำการแก้ไขอย่างไรดี ?
เมื่อไปค้นหาดูพบว่าอยู่ในไฟล์ config/database.php
จะพบว่ามีการ configuration ไว้ให้ 3 ตัวคือ SQLite, MySQL และ PostgreSQL
ดังนั้นเพื่อความรวดเร็ว ผมจึงเปลี่ยนไปใช้
SQLite ดีกว่า
ซึ่งเป็น In-memory database
จะได้ไม่ต้องติดตั้ง database อะไรเพิ่มอีก ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="config_database.php"]
จากนั้นทำการทดสอบรอบที่สาม
จะพบว่าข้อผิดพลาดแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่พบ database ใน SQLite ทำอย่างไรดี ?
ให้ทำการกำหนด environment ชื่อว่า DB_DATABASE ในไฟล์ phpunit.xml สิ
กำหนดค่าเป็น :memory: ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="phpunit.xml"]
จากนั้นทำการทดสอบรอบที่สี่
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่พบตาราง users ใน database
แล้วเราจะสร้างตาราง users ขึ้นมาอย่างไรดี ?
หลังจากที่ไปค้นหาและศึกษาพบว่า
Laravel framework มี migration tool ให้ใช้งาน แบบนี้ก็สบายเลย
ดังนั้นสั่งให้ทำการ migrate database ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="testcase_03.php"]
คำถามคือ แล้ว Laravel framework รู้ได้อย่างไรว่าจะสร้างอะไร ?
คำตอบคือ
ลองไปดูในไฟล์ database/factories/ModelFactory.php
และไฟล์ database/migrations/yyyy_mm_dd_create_users_table.php
แล้วจะถึงบางอ้อ
จากนั้นทำการทดสอบรอบที่ห้า
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ class Account ไม่มีใน Factory นั่นเอง
ดังนั้นให้ทำการเพิ่มเข้าไปซะ ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="ModelFactory_02.php"]
จากนั้นทำการทดสอบรอบที่หก
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ หา class Account ไม่เจอ ดังนั้นสร้างซะ
แต่ถ้าจะสร้างแบบ manual มันดูไม่งามนัก
เนื่องจาก Laravel framework ได้เตรียม command line ในการสร้าง model ได้ให้
ดังนั้นมาใช้กันหน่อยสิ
<pre>
[code]
$php artisan make:model Account
[/code]
จากนั้นทำการทดสอบรอบที่เจ็ด
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ใน class Users ไม่มี function ชื่อว่า accounts() นั่นเอง
ดังนั้นให้ทำการเพิ่มเข้าไปในสิ รออะไร
อีกอย่างที่ห้ามลืมก็คือ user แต่ละคนสามารถมา back account ได้มากกว่า 1 account นะ
เขียน code ได้ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="User_02.php"]
จากนั้นทำการทดสอบรอบที่แปด
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่มีตารางชื่อว่า accounts ใน database
ดังนั้นให้ทำการสร้างตารางด้วย migration tool กันเลย
ด้วยคำสั่งดังนี้
[code]
$php artisan make:migration create_accounts_table --create=accounts
[/code]
จะทำการสร้างไฟล์ใหม่ใน folder database/migration นะครับ
จากนั้นทำการทดสอบรอบที่เก้า
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่มี column ชื่อว่า account_no ในตาราง accounts
ด้วยการแก้ไขไฟล์ที่อยู่ใน folder database/migrations
ชื่อว่า create_accounts_table.php ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="create_accounts_table_01.php"]
จากนั้นทำการทดสอบรอบที่สิบ
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่มี column ชื่อว่า user_id ในตาราง accounts
ใช้สำหรับการอ้างอิงไปยังตาราง user นั่นเอง
ดังนั้นเพิ่มสิครับ
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="create_accounts_table_02.php"]
จากนั้นทำการทดสอบรอบที่สิบเอ็ด
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ 404 not found คือหา url ดังกล่าวไปเจอ
เห็นไหมว่า ปัญหามันวิ่งไปในส่วนของ View แล้วนะ
ก็แน่ล่ะ เพราะว่า เรายังไม่สร้างส่วนการแสดงผล และ url ดังกล่าวก็ยังไม่สร้าง !!
คำถามที่น่าสนใจคือ จะสร้างอย่างไรดีล่ะ ?
เมื่อไปอ่านเอกสารของ Laravel framework ก็พบว่า
ก่อนอื่นให้ทำการสร้าง Routing ของ url ที่เราต้องการขึ้นมาก่อน
รวมทั้งต้องระบุไปด้วยว่า จะจับคู่กับ class Controller อะไร และ function อะไร
และทำงานผ่าน HTTP GET ด้วย
โดยทำการเพิ่มในไฟล์ app/HTTP/route.php ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="route.php"]
จากนั้นทำการทดสอบรอบที่สิบสอง
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ถ้าสังเกตจะเห็นว่า
class UsersController ไม่มีนั่นเอง
ดังนั้นให้ทำการสร้างผ่าน command line อีกแล้ว ดังนี้
[code]
$php artisan make:controller UsersController
[/code]
จากนั้นทำการทดสอบรอบที่สิบสาม
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ใน class UsersController ไม่มี function ชื่อว่า show()
ดังนั้นให้ทำการเพิ่มดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="UsersController.php"]
จากนั้นทำการทดสอบรอบที่สิบสี่
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ผลการแสดงผลไม่ตรงตามที่ต้องการ
ดังนั้น สิ่งที่ต้องทำต่อไปคือ การสร้างส่วนของ view หรือ การแสดงผล
โดยต้องทำการดึงข้อมูลผู้ใช้งานจากตาราง User
เพื่อส่งไปแสดงผลใน view ต่อไป
ซึ่งต้องไปเปิดเอกสารของ Laravel framework ทำต่อไป ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="UsersController_02.php"]
จากนั้นทำการทดสอบรอบที่สิบห้า
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ เห็นไหมว่า Laravel framework หา view ไม่เจอ
ดังนั้นทำการสร้าง folder ชื่อง users ใน resources/views
โดย view นั้นจะใช้ Blade template
ทำการสร้างไฟล์ชื่อ show.blade.php ขึ้นมาดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="show.blade.php"]
จากนั้นทำการทดสอบรอบที่สิบหก
ผลที่ได้คือ ผ่านแล้ววววววววว
แสดงดังรูป
มาถึงตรงนี้ สิ่งที่ต้องถามตัวเราเองก็คือ
เราได้เรียนรู้อะไรเกี่ยวกับ Laravel framework กันบ้าง ?
แต่ยังไม่จบนะ ลองกลับไปดู code ใน UsersController ดูสิ มันแย่นะ !!
นั่นคือบรรทัดนี้
[code]
$user = User::where('name', $name)->first();
[/code]
มันอ่านไม่ค่อยรู้เรื่องนะ !!
รวมทั้งมันใช่หน้าที่ของ controller ที่ต้องมาทำแบบนี้หรือ ?
น่าจะต้องย้ายไปอยู่ใน class User หรือ model นะ
ดังนั้นเราจึงเข้าสู่การ refactor code
สังเกตไหมว่า จะทำการ refactoring code เมื่อชุดการทดสอบผ่านหมดแล้วเท่านั้น
เริ่มต้นการ Refactor code กันเถอะ
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="UsersController_03.php"]
แน่นอนว่าถ้า run ต้องเกิด error อย่างแน่นอน
เนื่องจากเรายังไม่เคยมี function findByName() ใน class User เลย
ดังนั้นมาเพิ่ม function นี้กันเถอะ
แต่ช้าก่อน !!
หยุดคิดหน่อยสิว่า เราพลาดอะไรไป ?
คำตอบคือ เรามาเขียน unit test สำหรับ class User กันดีกว่า
เพื่อทำให้มั่นใจว่า สิ่งที่เรากำลังจะสร้างมันถูกต้องตามที่คาดหวัง
โดยสร้าง unit test ชื่อว่า UserTest.php ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="UserTest.php"]
จากนั้นทำการทดสอบรอบที่สิบเจ็ด
ทำการทดสอบเฉพาะ class UserTest.php เท่านั้น
[code]
$./vendor/bin/phpunit tests/unit/UserTest.php
[/code]
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป
คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?
คำตอบคือ ไม่เจอ function findByName() ใน class User
ดังนั้นสร้างสิครับ ดังนี้
[gist id="6148dee2f9b64255a9d49575e0c1f612" file="User.php"]
จากนั้นทำการทดสอบรอบที่สิบแปด
ทำการทดสอบเฉพาะ class UserTest.php เท่านั้น
ผลที่ได้คือ ผ่านอีกแล้วววววว
เมื่อทุกอย่างพร้อมแล้ว เราก็ทำการทดสอบทั้งหมดอีกครั้งสิ
มันคือ Regression testing นั่นเอง
ซึ่งเรามีทั้งหมด 2 test case คือ Acceptance test และ Unit test
ได้ผลการทดสอบดังนี้
สำหรับใครที่เดินทางมาถึงตรงนี้
คิดอย่างไรกับวิธีการเรียนรู้ Laravel framework แบบนี้บ้าง ?
โดยรวมแล้วโครงสร้างของ Laravel framework มันก็เป็นประมาณนี้
สำหรับ code ตัวอย่างทั้งหมดอยู่ที่
Github::Laravel with TDD
Reference Websites
http://adamwathan.me/2016/01/11/test-driven-laravel-from-scratch/
https://vimeo.com/152727171?from=outro-embed