Quantcast
Channel: cc :: somkiat
Viewing all articles
Browse latest Browse all 1997

[PHP] เรียนรู้การพัฒนา Web Application ด้วย Laravel framework ตามแนวคิด Test Driven

$
0
0

learn-tdd

learn-tdd ถ้าต้องการศึกษา 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] ผลที่ได้แสดงดังรูป step_01

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่รู้จัก 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"] จากนั้นทำการทดสอบรอบที่สอง จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_02

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่สามารถติดต่อ 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"] จากนั้นทำการทดสอบรอบที่สาม จะพบว่าข้อผิดพลาดแตกต่างออกไป แสดงดังรูป step_03

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่พบ database ใน SQLite  ทำอย่างไรดี ? ให้ทำการกำหนด environment ชื่อว่า DB_DATABASE ในไฟล์ phpunit.xml สิ กำหนดค่าเป็น :memory: ดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="phpunit.xml"] จากนั้นทำการทดสอบรอบที่สี่ จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_04

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่พบตาราง 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 แล้วจะถึงบางอ้อ จากนั้นทำการทดสอบรอบที่ห้า จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_05

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ class Account ไม่มีใน Factory นั่นเอง ดังนั้นให้ทำการเพิ่มเข้าไปซะ ดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="ModelFactory_02.php"] จากนั้นทำการทดสอบรอบที่หก จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_06

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ หา class Account ไม่เจอ ดังนั้นสร้างซะ แต่ถ้าจะสร้างแบบ manual มันดูไม่งามนัก เนื่องจาก Laravel framework ได้เตรียม command line ในการสร้าง model ได้ให้ ดังนั้นมาใช้กันหน่อยสิ <pre> [code] $php artisan make:model Account [/code] จากนั้นทำการทดสอบรอบที่เจ็ด จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_07

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ใน class Users ไม่มี function ชื่อว่า accounts() นั่นเอง ดังนั้นให้ทำการเพิ่มเข้าไปในสิ รออะไร อีกอย่างที่ห้ามลืมก็คือ user แต่ละคนสามารถมา back account ได้มากกว่า 1 account นะ เขียน code ได้ดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="User_02.php"] จากนั้นทำการทดสอบรอบที่แปด จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_08

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่มีตารางชื่อว่า accounts ใน database ดังนั้นให้ทำการสร้างตารางด้วย migration tool กันเลย ด้วยคำสั่งดังนี้ [code] $php artisan make:migration create_accounts_table --create=accounts [/code] จะทำการสร้างไฟล์ใหม่ใน folder database/migration นะครับ จากนั้นทำการทดสอบรอบที่เก้า จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_09

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่มี column ชื่อว่า account_no ในตาราง accounts ด้วยการแก้ไขไฟล์ที่อยู่ใน folder database/migrations ชื่อว่า create_accounts_table.php ดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="create_accounts_table_01.php"] จากนั้นทำการทดสอบรอบที่สิบ จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_10

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่มี column ชื่อว่า user_id ในตาราง accounts ใช้สำหรับการอ้างอิงไปยังตาราง user นั่นเอง ดังนั้นเพิ่มสิครับ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="create_accounts_table_02.php"] จากนั้นทำการทดสอบรอบที่สิบเอ็ด จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_11

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ 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"] จากนั้นทำการทดสอบรอบที่สิบสอง จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_12

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ถ้าสังเกตจะเห็นว่า class UsersController ไม่มีนั่นเอง ดังนั้นให้ทำการสร้างผ่าน command line อีกแล้ว ดังนี้ [code] $php artisan make:controller UsersController [/code] จากนั้นทำการทดสอบรอบที่สิบสาม จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_13

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ใน class UsersController ไม่มี function ชื่อว่า show() ดังนั้นให้ทำการเพิ่มดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="UsersController.php"] จากนั้นทำการทดสอบรอบที่สิบสี่ จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_14

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ผลการแสดงผลไม่ตรงตามที่ต้องการ ดังนั้น สิ่งที่ต้องทำต่อไปคือ การสร้างส่วนของ view หรือ การแสดงผล โดยต้องทำการดึงข้อมูลผู้ใช้งานจากตาราง User เพื่อส่งไปแสดงผลใน view ต่อไป ซึ่งต้องไปเปิดเอกสารของ Laravel framework ทำต่อไป ดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="UsersController_02.php"] จากนั้นทำการทดสอบรอบที่สิบห้า จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_15

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ เห็นไหมว่า Laravel framework หา view ไม่เจอ ดังนั้นทำการสร้าง folder ชื่อง users ใน resources/views โดย view นั้นจะใช้ Blade template ทำการสร้างไฟล์ชื่อ show.blade.php ขึ้นมาดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="show.blade.php"] จากนั้นทำการทดสอบรอบที่สิบหก ผลที่ได้คือ ผ่านแล้ววววววววว แสดงดังรูป step_16
มาถึงตรงนี้ สิ่งที่ต้องถามตัวเราเองก็คือ เราได้เรียนรู้อะไรเกี่ยวกับ 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] จะพบว่าข้อผิดพลาดมันแตกต่างออกไป แสดงดังรูป step_17

คำถามคือ ปัญหาของข้อผิดพลาดนี้คืออะไร ?

คำตอบคือ ไม่เจอ function findByName() ใน class User ดังนั้นสร้างสิครับ ดังนี้ [gist id="6148dee2f9b64255a9d49575e0c1f612" file="User.php"] จากนั้นทำการทดสอบรอบที่สิบแปด ทำการทดสอบเฉพาะ class UserTest.php เท่านั้น ผลที่ได้คือ ผ่านอีกแล้วววววว step_18

เมื่อทุกอย่างพร้อมแล้ว เราก็ทำการทดสอบทั้งหมดอีกครั้งสิ

มันคือ Regression testing นั่นเอง ซึ่งเรามีทั้งหมด 2 test case คือ Acceptance test และ Unit test ได้ผลการทดสอบดังนี้ step_19
สำหรับใครที่เดินทางมาถึงตรงนี้ คิดอย่างไรกับวิธีการเรียนรู้ Laravel framework แบบนี้บ้าง ?
โดยรวมแล้วโครงสร้างของ Laravel framework มันก็เป็นประมาณนี้ laravel-mvc-components สำหรับ 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

Viewing all articles
Browse latest Browse all 1997

Trending Articles