ข้ามไปยังเนื้อหา
แก่น Kaen
ค้นหา
Ctrl
K
ยกเลิก
เลือกธีม
มืด
สว่าง
อัตโนมัติ
ทดสอบ app DDD/Clean Architecture ให้เป็น
พิสูจน์ว่าโครงและ domain ที่สร้างมาทำงานถูกจริง — 8 บทเรียนทดสอบ domain Order เดิม ตั้งแต่ยูนิตจนถึง e2e
เริ่มบทที่ 1
ความคืบหน้า
0 / 8 บทเรียน
เส้นทางการเรียน
หัวข้อที่มีชื่อว่า “เส้นทางการเรียน”
●
01
ทำไมสถาปัตยกรรมนี้ test ง่าย
เริ่มตรงนี้
Testability
คุณสมบัติที่ระบบถูกทดสอบได้ง่ายโดยเนื้อแท้ เป็นผลพลอยได้ของการกลับทิศ dependency (Dependency Rule) — domain ที่ไม่พึ่งภายนอกเลยทดสอบตรง ๆ ได้โดยไม่ต้อง mock อะไรเลย
Test Pyramid
กรอบคิดของ Fowler ที่จัดสัดส่วน test เป็นชั้น: unit test เยอะสุดอยู่ฐาน (เร็ว ถูก) → integration test รองลงมา → e2e test น้อยสุดอยู่ยอด (ช้า แพง แต่มั่นใจสุด) — ยิ่งขึ้นสูงยิ่ง test น้อยลงแต่ขอบเขตกว้างขึ้น
○
02
ยูนิต test domain — ไม่ต้อง mock
Unit Test
test หน่วยเล็กที่สุดแบบแยกตัว รันเร็ว ไม่พึ่ง DB/เครือข่าย/เวลาจริง — ใน domain บริสุทธิ์อย่าง Order ทดสอบได้ตรง ๆ โดยไม่ต้อง mock อะไรเลย
Arrange-Act-Assert (AAA)
โครงสามส่วนของ test ที่ดี: Arrange (จัดเตรียมข้อมูล/dependency), Act (เรียกพฤติกรรมที่ต้องการทดสอบ), Assert (ตรวจผลลัพธ์) — ทำให้ test อ่านง่ายและมีจุดโฟกัสเดียว
○
03
สี่เสาหลักของ test ที่ดี
Four Pillars of a Good Test
เกณฑ์สี่ข้อของ test ที่ดีจากหนังสือของ Khorikov: กันรีเกรสชัน (protection against regressions), ทนต่อการ refactor (resistance to refactoring), ฟีดแบ็กเร็ว (fast feedback), และดูแลรักษาง่าย (maintainability) — test ที่ดีต้องได้สมดุลของทั้งสี่
Resistance to Refactoring
คุณสมบัติที่ test ไม่พังเวลา refactor code ที่ยังทำงานถูก — test ที่ผูกกับ 'วิธีทำ' (implementation detail) แทน 'ผลลัพธ์' จะเปราะและเตือนหลอกบ่อย
○
04
Test Doubles — mock/stub/fake/spy/dummy
Test Double
ของปลอมที่ใช้แทน dependency จริงใน test (Fowler แบ่งเป็น dummy/stub/spy/mock/fake) เพื่อตัดสิ่งที่ช้า/ไม่แน่นอน/ยากออก แล้วโฟกัสที่พฤติกรรมที่กำลังทดสอบ
Mock
test double ที่ 'ตรวจว่ามีการเรียกเกิดขึ้น' (interaction-based) เช่น ยืนยันว่า ChargeAsync ถูกเรียกด้วยจำนวนเงินที่ถูกต้อง — ใช้เมื่อสิ่งที่สนใจคือ 'สิ่งที่เกิดขึ้น' ไม่ใช่สถานะ
○
05
test use case ด้วย test double
Fake
test double ที่ implement ใช้งานได้จริงแต่เบากว่าของจริง เช่น FakePaymentGateway ที่บันทึก Charges/Refunds ไว้ใน list แทนการยิงเครือข่ายจริง — ตรวจผลลัพธ์ผ่านสถานะได้โดยไม่ต้อง verify interaction
Sociable Test
test ที่ให้อ็อบเจ็กต์จริงทำงานร่วมกันจริง เช่น handler คุยกับ Order จริง แต่ fake เฉพาะ port วงนอก (DB/gateway) — ตรงข้ามกับ solitary test ที่ mock ทุกอย่างรอบตัว class ที่ทดสอบ
○
06
Integration test ด้วย Testcontainers
Integration Test
test ที่ตรวจว่า code ของเราคุยกับของภายนอกจริงได้ถูกต้อง เช่น repository กับฐานข้อมูลจริง — ช้ากว่า unit test แต่จับ bug mapping/SQL ที่ unit test มองไม่เห็น
Testcontainers
library ที่สปินอินฟราจริง (เช่น Postgres) ขึ้นมาใน Docker container ชั่วคราวสำหรับรัน test แต่ละครั้ง แล้วทิ้งทันทีหลังจบ — ได้ฐานข้อมูลจริงโดยไม่ต้องดูแล instance ถาวร
○
07
E2E ผ่าน API จริง
End-to-End Test (E2E)
test ที่ขับทั้งระบบผ่านช่องทางเดียวกับผู้ใช้จริง เช่น ยิง HTTP request เข้า API แล้วตรวจ response — ให้ความมั่นใจสูงสุดแต่ช้าและเปราะที่สุด จึงมีน้อยที่สุดในพีระมิด
System Under Test (SUT)
ส่วนของระบบที่กำลังถูกทดสอบใน test หนึ่ง ๆ ขอบเขตกว้าง-แคบต่างกันตามระดับ: unit test มี SUT แคบแค่ class เดียว ส่วน e2e test มี SUT กว้างทั้ง app
○
08
อะไรที่ "ไม่ควร" test
Brittle Test
test ที่พังเวลา refactor code ทั้งที่พฤติกรรมยังถูกต้อง มักเกิดจากผูกกับรายละเอียดภายใน (private field, ลำดับการเรียก) แทนผลลัพธ์ที่สังเกตได้จากภายนอก
Test Coverage
สัดส่วน code ที่ถูกรันระหว่าง test วัดแค่ 'การรัน' ไม่ได้วัดว่า assert ตรวจอะไรบ้าง — 100% coverage ไม่ได้แปลว่า test ดี