learn-tdd
ถ้าต้องการศึกษา Laravel framework ซึ่งเป็นสิ่งใหม่สำหรับผม
คำถามที่น่าสนใจก็คือ จะทำการศึกษา และ เรียนรู้ ฝึกทำอย่างไรดีล่ะ ?
คำตอบนั้นมีอยู่หลายแบบ
แต่สำหรับผมแล้ว ขอเริ่มจากการเขียน test หรือ ชุดการทดสอบดีกว่า !!
ดังนั้นมาเริ่มกันเลย

ปล. ไม่พูดถึงการสร้าง project และเตรียม environment นะครับ

มีเป้าหมายหลักเพื่อ

เรียนรู้การพัฒนาระบบด้วย Laravel framework
เรียนรู้โครงสร้างการทำงานพื้นฐานของ Laravel framework เช่น

  • Factory
  • Model ซึ่งมี ORM มาให้
  • Database migration
  • Routing
  • Controller
  • View

เริ่มด้วยการเขียนชุดการทดสอบในระดับ Acceptance Test

โดยสิ่งที่ต้องการคือ ขั้นตอนการสร้างบัญชีธนาคารของผู้ใช้งาน
ดังนั้นการทำงานมีขั้นตอนดังนี้

  • สร้างผู้ใช้งาน
  • สร้างบัญชีธนาคารใหม่
  • ตรวจสอบผลการสร้างบัญชีใหม่ ว่าแสดงผลหมายเลขบัญชีใหม่ถูกต้องหรือไม่

สามารถเขียนชุดการทดสอบด้วย PHPUnit ดังนี้

ทำการทดสอบด้วยคำสั่ง

$./vendor/bin/phpunit

ผลที่ได้แสดงดังรูป

step_01

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

คำตอบคือ ไม่รู้จัก User ใน Factory !!!
แต่ประเด็นหลักคือ Factory ของ Model คืออะไร ?
และมันอยู่ตรงไหนล่ะ ?
ตอบง่าย ๆ คือ โรงงานผลิต Model ไงล่ะ
ใครอยากจะจัดการข้อมูลผ่าน database ก็มาหาจากที่นี่ได้เลย

เมื่อลองไปค้นหาใน project พบว่าอยู่ในไฟล์ database/factories/ModelFactory.php นั่นเอง
แสดงดังนี้

จาก code ดังกล่าว
จะเห็นได้ว่าใน factory มี User อยู่แล้ว
แต่ว่า User มันอยู่ใน namspace ชื่อว่า App
ดังนั้นสิ่งที่เราควรทำคือ ในชุดการทดสอบ
ให้ทำการ import หรือ use App\User สิครับ ดังนี้

จากนั้นทำการทดสอบรอบที่สอง
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_02

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

คำตอบคือ ไม่สามารถติดต่อ MySQL database ได้ไง
แสดงว่า default database ของ Laravel framework คือ MySQL นั่นเอง
ได้ความรู้ใหม่กันอีกแล้ว

คำถามต่อมาคือ จะทำการแก้ไขอย่างไรดี ?
เมื่อไปค้นหาดูพบว่าอยู่ในไฟล์ config/database.php
จะพบว่ามีการ configuration ไว้ให้ 3 ตัวคือ SQLite, MySQL และ PostgreSQL
ดังนั้นเพื่อความรวดเร็ว ผมจึงเปลี่ยนไปใช้ SQLite ดีกว่า
ซึ่งเป็น In-memory database
จะได้ไม่ต้องติดตั้ง database อะไรเพิ่มอีก ดังนี้

จากนั้นทำการทดสอบรอบที่สาม
จะพบว่าข้อผิดพลาดแตกต่างออกไป
แสดงดังรูป

step_03

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

คำตอบคือ ไม่พบ database ใน SQLite  ทำอย่างไรดี ?
ให้ทำการกำหนด environment ชื่อว่า DB_DATABASE ในไฟล์ phpunit.xml สิ
กำหนดค่าเป็น :memory: ดังนี้

จากนั้นทำการทดสอบรอบที่สี่
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_04

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

คำตอบคือ ไม่พบตาราง users ใน database
แล้วเราจะสร้างตาราง users ขึ้นมาอย่างไรดี ?

หลังจากที่ไปค้นหาและศึกษาพบว่า
Laravel framework มี migration tool ให้ใช้งาน แบบนี้ก็สบายเลย
ดังนั้นสั่งให้ทำการ migrate database ดังนี้

คำถามคือ แล้ว Laravel framework รู้ได้อย่างไรว่าจะสร้างอะไร ?
คำตอบคือ
ลองไปดูในไฟล์ database/factories/ModelFactory.php
และไฟล์ database/migrations/yyyy_mm_dd_create_users_table.php
แล้วจะถึงบางอ้อ

จากนั้นทำการทดสอบรอบที่ห้า
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_05

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

คำตอบคือ class Account ไม่มีใน Factory นั่นเอง
ดังนั้นให้ทำการเพิ่มเข้าไปซะ ดังนี้

จากนั้นทำการทดสอบรอบที่หก
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_06

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

คำตอบคือ หา class Account ไม่เจอ ดังนั้นสร้างซะ
แต่ถ้าจะสร้างแบบ manual มันดูไม่งามนัก
เนื่องจาก Laravel framework ได้เตรียม command line ในการสร้าง model ได้ให้
ดังนั้นมาใช้กันหน่อยสิ
<pre>

$php artisan make:model Account

จากนั้นทำการทดสอบรอบที่เจ็ด
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_07

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

คำตอบคือ ใน class Users ไม่มี function ชื่อว่า accounts() นั่นเอง
ดังนั้นให้ทำการเพิ่มเข้าไปในสิ รออะไร
อีกอย่างที่ห้ามลืมก็คือ user แต่ละคนสามารถมา back account ได้มากกว่า 1 account นะ
เขียน code ได้ดังนี้

จากนั้นทำการทดสอบรอบที่แปด
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_08

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

คำตอบคือ ไม่มีตารางชื่อว่า accounts ใน database
ดังนั้นให้ทำการสร้างตารางด้วย migration tool กันเลย
ด้วยคำสั่งดังนี้

$php artisan make:migration create_accounts_table --create=accounts

จะทำการสร้างไฟล์ใหม่ใน folder database/migration นะครับ
จากนั้นทำการทดสอบรอบที่เก้า
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_09

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

คำตอบคือ ไม่มี column ชื่อว่า account_no ในตาราง accounts
ด้วยการแก้ไขไฟล์ที่อยู่ใน folder database/migrations
ชื่อว่า create_accounts_table.php ดังนี้

จากนั้นทำการทดสอบรอบที่สิบ
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_10

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

คำตอบคือ ไม่มี column ชื่อว่า user_id ในตาราง accounts
ใช้สำหรับการอ้างอิงไปยังตาราง user นั่นเอง
ดังนั้นเพิ่มสิครับ

จากนั้นทำการทดสอบรอบที่สิบเอ็ด
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_11

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

คำตอบคือ 404 not found คือหา url ดังกล่าวไปเจอ
เห็นไหมว่า ปัญหามันวิ่งไปในส่วนของ View แล้วนะ
ก็แน่ล่ะ เพราะว่า เรายังไม่สร้างส่วนการแสดงผล และ url ดังกล่าวก็ยังไม่สร้าง !!

คำถามที่น่าสนใจคือ จะสร้างอย่างไรดีล่ะ ?
เมื่อไปอ่านเอกสารของ Laravel framework ก็พบว่า
ก่อนอื่นให้ทำการสร้าง Routing ของ url ที่เราต้องการขึ้นมาก่อน
รวมทั้งต้องระบุไปด้วยว่า จะจับคู่กับ class Controller อะไร และ function อะไร
และทำงานผ่าน HTTP GET ด้วย
โดยทำการเพิ่มในไฟล์ app/HTTP/route.php ดังนี้

จากนั้นทำการทดสอบรอบที่สิบสอง
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_12

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

คำตอบคือ ถ้าสังเกตจะเห็นว่า class UsersController ไม่มีนั่นเอง
ดังนั้นให้ทำการสร้างผ่าน command line อีกแล้ว ดังนี้

$php artisan make:controller UsersController

จากนั้นทำการทดสอบรอบที่สิบสาม
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_13

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

คำตอบคือ ใน class UsersController ไม่มี function ชื่อว่า show()
ดังนั้นให้ทำการเพิ่มดังนี้

จากนั้นทำการทดสอบรอบที่สิบสี่
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_14

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

คำตอบคือ ผลการแสดงผลไม่ตรงตามที่ต้องการ
ดังนั้น สิ่งที่ต้องทำต่อไปคือ การสร้างส่วนของ view หรือ การแสดงผล
โดยต้องทำการดึงข้อมูลผู้ใช้งานจากตาราง User
เพื่อส่งไปแสดงผลใน view ต่อไป
ซึ่งต้องไปเปิดเอกสารของ Laravel framework ทำต่อไป ดังนี้

จากนั้นทำการทดสอบรอบที่สิบห้า
จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_15

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

คำตอบคือ เห็นไหมว่า Laravel framework หา view ไม่เจอ
ดังนั้นทำการสร้าง folder ชื่อง users ใน resources/views
โดย view นั้นจะใช้ Blade template
ทำการสร้างไฟล์ชื่อ show.blade.php ขึ้นมาดังนี้

จากนั้นทำการทดสอบรอบที่สิบหก
ผลที่ได้คือ ผ่านแล้ววววววววว
แสดงดังรูป

step_16

มาถึงตรงนี้ สิ่งที่ต้องถามตัวเราเองก็คือ
เราได้เรียนรู้อะไรเกี่ยวกับ Laravel framework กันบ้าง ?

แต่ยังไม่จบนะ ลองกลับไปดู code ใน UsersController ดูสิ มันแย่นะ !!
นั่นคือบรรทัดนี้

$user = User::where('name', $name)->first();

มันอ่านไม่ค่อยรู้เรื่องนะ !!
รวมทั้งมันใช่หน้าที่ของ controller ที่ต้องมาทำแบบนี้หรือ ?
น่าจะต้องย้ายไปอยู่ใน class User หรือ model นะ
ดังนั้นเราจึงเข้าสู่การ refactor code
สังเกตไหมว่า จะทำการ refactoring code เมื่อชุดการทดสอบผ่านหมดแล้วเท่านั้น

เริ่มต้นการ Refactor code กันเถอะ

แน่นอนว่าถ้า run ต้องเกิด error อย่างแน่นอน
เนื่องจากเรายังไม่เคยมี function findByName() ใน class User เลย
ดังนั้นมาเพิ่ม function นี้กันเถอะ

แต่ช้าก่อน !!
หยุดคิดหน่อยสิว่า เราพลาดอะไรไป ?

คำตอบคือ เรามาเขียน unit test สำหรับ class User กันดีกว่า
เพื่อทำให้มั่นใจว่า สิ่งที่เรากำลังจะสร้างมันถูกต้องตามที่คาดหวัง
โดยสร้าง unit test ชื่อว่า UserTest.php ดังนี้

จากนั้นทำการทดสอบรอบที่สิบเจ็ด
ทำการทดสอบเฉพาะ class UserTest.php เท่านั้น

$./vendor/bin/phpunit tests/unit/UserTest.php 

จะพบว่าข้อผิดพลาดมันแตกต่างออกไป
แสดงดังรูป

step_17

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

คำตอบคือ ไม่เจอ function findByName() ใน class User
ดังนั้นสร้างสิครับ ดังนี้

จากนั้นทำการทดสอบรอบที่สิบแปด
ทำการทดสอบเฉพาะ 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