← Back to PostgreSQL course
PHASE 3: DEVOPS, MAINTAINABILITY & ARCHITECTURAL BOUNDARIES QUALITY GATE 🧪

Day 12: Automated Testing with Testcontainers & pgTAP (การทำ Automated Database Unit Testing ด้วย pgTAP, การจำลอง Ephemeral Database Container ด้วย Testcontainers ใน CI/CD Pipeline, และการสร้าง Test Isolation ในระดับ Transaction)

ยกเลิกการ Manual Test บน Shared Staging DB ที่ข้อมูลตีกันจนพัง! ยกระดับความมั่นใจใน Stored Units (UDFs, Procedures, Triggers) สู่สถาปัตยกรรม Shift-Left Automated Quality Gate เขียน Unit Test ในภาษา SQL ด้วย pgTAP ควบคู่กับการสปินอัป Ephemeral Database บน CI/CD ด้วย Testcontainers การันตีความสะอาด 100% ด้วย Transactional Isolation (ROLLBACK) ไร้ Regression Bugs ก่อนถึง Production!

📍 ตำแหน่งปัจจุบันของคุณบน Roadmap (18-Day Masterclass) Phase 3: Pillar 03 Quality & Automation
Phase 1: Architecture Synthesis (Days 1–4) ✓
➔
Phase 2: 4 Pillars & Capstone (Days 5–10) ✓
➔
Day 11: Database-as-Code & Flyway ✓
➔
Day 12: Automated Testing (pgTAP & Testcontainers)
➔ ➔
เปิดบท

ถอดรหัสคำสำคัญของวันนี้

โค้ดฐานข้อมูลเข้า Git แล้ว คำถามถัดไปคือจะรู้ได้อย่างไรว่า Pull Request วันนี้ไม่ทำลาย logic เดิม — วันนี้คือการทดสอบอัตโนมัติบนฐานข้อมูลชั่วคราวที่สร้างขึ้นมาแล้วทิ้ง

Automated Testing

การเขียนโปรแกรมทดสอบให้อัตโนมัติ เพื่อเช็คความถูกต้องของ business logic โดยไม่ต้องให้คนมานั่งกดทดสอบด้วยมือ

pgTAP

เครื่องมือเขียน unit test ให้ stored code ใน PostgreSQL ด้วยภาษา SQL / PL/pgSQL

Testcontainers

เครื่องมือที่สปินอัปตู้คอนเทนเนอร์ฐานข้อมูลชั่วคราวขึ้นมารันเทสบน CI/CD แล้วลบทิ้งทันทีเมื่อรันเสร็จ เพื่อความสะอาดร้อยเปอร์เซ็นต์

โดยรวมวันนี้คือระบบทดสอบที่สร้างฐานข้อมูลชั่วคราวขึ้นมา รัน Flyway migration แล้วยิง pgTAP ตรวจ stored units ทุกตัว ก่อนสั่ง rollback และลบฐานข้อมูลทิ้ง

เปรียบกับชีวิตจริง

เหมือนสนามสอบชนหุ่นยนต์จำลอง ก่อนเอาหุ่นยนต์จริงไปวิ่งบนถนน เราสร้างสนามจำลองสะอาดๆ ให้วิ่งทดสอบเป็นร้อยด่านในไม่กี่วินาที พอเสร็จก็ทุบสนามทิ้ง โดยไม่ทำให้ถนนจริงเสียหาย

ช่วยดักบั๊กตั้งแต่ตอนเปิด Pull Request (shift-left testing) การันตีว่าการแก้โค้ดวันนี้จะไม่ไปทำลายการทำงานเดิมที่มีอยู่

1

🏛️ มโนทัศน์ สถาปัตยกรรมองค์กร และสถานการณ์จริง (Concept & Architecture)

หลังจากที่เราได้นำ Stored Units เข้าสู่ Version Control ด้วย Flyway (Day 11) คำถามสำคัญระดับ Enterprise ที่สถาปนิกและหัวหน้าทีมพัฒนามักตั้งคำถามเสมอคือ "เมื่อมีนักพัฒนา 30 คนส่ง Pull Request เข้ามาแก้ไข Stored Procedures และ Triggers เราจะการันตีได้อย่างไรว่าโค้ดใหม่จะไม่ไปทำลาย Business Logic เดิมที่มีอยู่?"

💥 บทเรียนจริงจากสมรภูมิระดับโลก: Wise & Nubank กับหายนะ Shared Staging Data Pollution
ในระบบโอนเงินข้ามประเทศของ Wise (TransferWise) และธนาคารดิจิทัลที่ใหญ่ที่สุดในละตินอเมริกาอย่าง Nubank มีวิศวกรซอฟต์แวร์นับร้อยทีมทำงานกับฐานข้อมูลธุรกรรมหลัก ในอดีตทั้งสององค์กรเคยพึ่งพา Shared Staging Database เดียวกันสำหรับการทดสอบระบบก่อนขึ้น Production

วิกฤตเกิดขึ้นเมื่อทีมหนึ่งรัน Test Case ดอกเบี้ยผิดนัดชำระที่ไปเปลี่ยนสถานะบัญชีทดสอบใน Staging DB แต่ ไม่ได้เขียนสคริปต์ล้างข้อมูล (No Cleanup) เมื่ออีกทีมเข้ามารัน Test คำนวณยอดเงินโอน ผลลัพธ์จึงพังทลายกลายเป็น "Flaky Tests มหาศาล" ทีมงานเข้าใจผิดคิดว่าเป็นบั๊กที่โค้ด เสียเวลาไล่ดีบั๊กนานกว่า 4 วัน! และเมื่อมีเคสหลุดรอดไปถึง Production ก็เกิดการปัดเศษเงินทศนิยมผิดพลาดจนสูญเงินหลายล้านบาท!

ทางออกของทั้งสององค์กรคือการนำ Shift-Left Testing ผ่าน Testcontainers มาใช้ใน CI/CD: "ทุก Pull Request จะต้องได้รับ Ephemeral Database Container สะอาดเอี่ยมเป็นของตัวเอง รัน Flyway, รัน Database Unit Tests ด้วย pgTAP ให้ผ่าน 100% แล้วทุบ Container ทิ้งทันที ไม่อนุญาตให้ใช้ Shared DB รันเทสต์อีกต่อไป!"
🎯 บทเรียนสำคัญ: การทดสอบฐานข้อมูลบน Shared Staging คือกับดักลวงตา ความน่าเชื่อถือของ Test Suite จะเกิดขึ้นได้ก็ต่อเมื่อแต่ละการทดสอบมีสภาพแวดล้อมที่สะอาด 100% (Clean State) เท่านั้น!
🚨 วิกฤตคำนวณส่วนลดติดลบ 5 ล้านบาท: เมื่อการ Manual Test บน Staging นำไปสู่หายนะ Production

องค์กรด้านการชำระเงินดิจิทัลแห่งหนึ่ง มี Stored Procedures และ Triggers คำนวณค่าธรรมเนียมและสิทธิประโยชน์ลูกค้ารวมกันกว่า 300 โปรแกรมยูนิต ทุกครั้งที่มีการเปลี่ยน Business Logic ทีม QA ต้องใช้เวลา Manual Test นานกว่า 3 วัน โดยการยิง API ผ่าน Postman เข้าไปยัง Shared Staging Database:

Data Pollution
Staging DB ติด State เสียหาย ขยะข้อมูลสะสม
Flaky Tests 40%
รันผ่านบ้างไม่ผ่านบ้างเพราะข้อมูลชนกัน
5,000,000 บาท
สูญเสียทางบัญชีใน 2 ชม. จาก Edge Case บั๊กหลุด

ต้นตอของวิกฤตนี้คือ "การขาด Automated Unit Test ในระดับ Database Logic" ทางออกเดียวในระดับ Enterprise คือการย้ายการทดสอบมาอยู่ใน CI/CD แบบ Shift-Left Testing ด้วย pgTAP และ Testcontainers ครับ!

🧪 อุปมาอุปไมย: ห้องครัวส่วนกลางที่สกปรก vs หลอดทดลองวิทยาศาสตร์ปลอดเชื้อใช้ครั้งเดียวทิ้ง

❌ Shared Staging DB (ห้องครัวส่วนกลางที่เชฟ 30 คนแย่งกันทำอาหาร)

เปรียบเหมือนเชฟ 30 คนทำอาหารในครัวเดียวกัน เชฟคนแรกเทน้ำปลาลงในหม้อซุปเพื่อชิม (Data Pollution) แล้วเดินออกไป

  • เชฟคนที่สองเข้ามาทำของหวาน ชิมซุปแล้วบอกว่า "สูตรหวานพัง" ทั้งที่เกิดจากน้ำปลาของคนแรก (Flaky Test)
  • ใช้เวลานาน 3 วันในการไล่ล้างทำความสะอาดครัว (Manual Test นานและเหนื่อยล้า)
  • ไม่สามารถการันตีความถูกต้องของสูตรอาหารได้เลย
✅ Ephemeral Testcontainers + pgTAP (หลอดทดลองปลอดเชื้อ 100%)

เปรียบเหมือนนักวิทยาศาสตร์ที่ใช้หลอดทดลองสูญญากาศปลอดเชื้อแบบ Single-use หยดสารเคมีลงไปทดสอบ แล้วทิ้งทันที

  • สะอาด 100% ทุกครั้ง: CI/CD สปินอัป PostgreSQL ใหม่เอี่ยม รัน Flyway แล้วยิง pgTAP ตรวจสอบ
  • Transactional Isolation: แต่ละ Test Case ครอบด้วย BEGIN; ... ROLLBACK; ไม่ทิ้งสารตกค้าง
  • เร็วทันใจ: รันการทดสอบ 100 เคสจบใน 5 วินาที บน GitHub Actions ก่อน Merge โค้ด!

⚖️ การเปรียบเทียบเชิงสถาปัตยกรรม: Manual Staging Testing vs. Automated pgTAP + Testcontainers

มิติเปรียบเทียบสถาปัตยกรรม แบบเดิม (Shared Staging DB Manual Test) แบบใหม่ (Automated pgTAP + Testcontainers)
สภาพแวดล้อมฐานข้อมูล (Environment) Shared Staging DB (ฐานข้อมูลตัวเดียว ใช้ร่วมกันทั้งทีม) Ephemeral Container (สปินอัปใหม่และทำลายทิ้งอัตโนมัติ)
ระดับการทดสอบ (Testing Scope) Black-box ยิง API ผ่าน Postman (ไม่เห็น Logic ข้างใน) White-box Unit Testing ทดสอบ Stored Units ถึงระดับฟังก์ชัน
ความบริสุทธิ์ของข้อมูล (Data Isolation) เกิด Data Pollution ขยะข้อมูลสะสมจนเกิด Flaky Tests 100% Clean State ด้วย BEGIN; ... ROLLBACK;
ระยะเวลาในการรัน Test (Feedback Loop) 3 วัน (QA ต้องไล่ทดสอบด้วยมือทีละหน้าจอ) 5-10 วินาที (รันอัตโนมัติบน Pull Request CI/CD Pipeline)
การป้องกัน Regression Bugs ต่ำมาก (บั๊ก Edge Cases หลุดรอดไปถึง Production เสมอ) เกราะป้องกัน 100% (Quality Gate) ห้าม Merge ถ้าเทสต์ไม่ผ่าน
สถาปัตยกรรมระดับลึก: การไหลของ Shift-Left Automated Testing บน CI/CD ด้วย Testcontainers & pgTAP Automated Quality Gate Pipeline
❌ แย่: Manual Test บน Shared Staging DB (ข้อมูลชนกัน บั๊กหลุด) ✅ ปัง: Shift-Left Automated Testing (Testcontainers + pgTAP Quality Gate) 1. Shared Staging DB & Data Pollution • นักพัฒนา 15 คนรันเทสต์ชนกันใน Staging DB ตัวเดียวกัน • ข้อมูลถูกแก้คาไว้ ไม่มีการ Rollback (Data Pollution) ⚠️ เกิด Flaky Tests เทสต์ผ่านบ้างไม่ผ่านบ้างจนทีมเลิกเชื่อผลเทสต์! 2. Manual Postman Testing (3 วันเต็ม) • QA ต้องใช้มือกดส่ง Request ทีละตัว ตรวจสอบผลลัพธ์ในตาราง • ตรวจสอบได้เฉพาะเคสปกติ (Happy Path) ขาดการเช็ค Edge Cases • Release Cycle ล่าช้า และสูญเสียงบประมาณด้านทรัพยากรบุคคล 💥 บั๊กหลุดรอดขึ้น Production คำนวณส่วนลดติดลบ เสียหาย 5 ล้านบาท! ผลกระทบต่อองค์กร: ขาด Automated Safety Net • สถาปัตยกรรมไร้ความน่าเชื่อถือ ทีมกลัวการ Deploy Stored Code • ไม่สามารถทำ Continuous Delivery (CD) ได้จริง สูญเสียความเชื่อมั่นจากลูกค้าและคณะกรรมการตรวจสอบ 1. GitHub Actions / GitLab CI Pull Request Trigger • นักพัฒนาเปิด Pull Request แก้ไข Stored Units ใน Git ⚡ Testcontainers สปินอัป Ephemeral PostgreSQL 16 (Clean State) • Flyway รัน Migration ปูโครงสร้าง Schema และ Procedures สดๆ • ติดตั้ง Extension pgTAP พร้อมรัน Test Suite ทันที 2. pgTAP In-Database Assertion Suite (Zero Data Pollution) BEGIN; ➔ plan(100); ➔ is() / results_eq() ➔ finish(); ➔ ROLLBACK; ทดสอบครอบคลุมทุก Edge Case ข้อมูลทั้งหมดถูก Rollback ทิ้ง 100% • หาก Test ผ่าน 100% ➔ Quality Gate อนุมัติ Merge โค้ด • หากล้มเหลวแม้แต่ข้อเดียว ➔ Reject PR ทันที ป้องกันบั๊กขึ้น Prod! ผลลัพธ์: ตรวจสอบ 100+ เคสใน 5 วินาที (จากเดิม 3 วัน) ขจัด Regression Bugs 100%, คอนเทนเนอร์ถูกทำลายทิ้งทันที ไร้ขยะตกค้าง
🎙️ สคริปต์คำพูดสำหรับพรีเซนท์บนเวที (Presentation Pitch Script)

"ทุกท่านครับ การทดสอบ Stored Procedure ด้วยการต่อ API ยิงเข้า Staging DB คือการทำงานแบบสะเปะสะปะที่สร้างปัญหา Data Pollution และล้มเหลวในการดักจับ Edge Cases!

ด้วย Day 12 Architecture เราจะเปลี่ยนมาใช้ pgTAP เขียน Unit Test ระดับ Database Logic ควบคู่กับ Testcontainers บน CI/CD Pipeline ทุกครั้งที่มี Pull Request ระบบจะสร้าง Ephemeral PostgreSQL ขึ้นมารัน Flyway แล้วยิง pgTAP ตรวจสอบความถูกต้องกว่า 100 เคสใน 5 วินาที พร้อม Rollback ข้อมูลทิ้ง 100%!

ผลลัพธ์คือการขจัด Regression Bugs ก่อนถึง Production ได้ 100% ลดเวลาการทดสอบจาก 3 วันเหลือเพียง 10 วินาที และการันตีว่า Stored Code ของเรามีความแม่นยำระดับ Mission-Critical ครับ"

🧮 วิดเจ็ตทดลอง: ตัวจำลองการทำงานของ Testcontainers & pgTAP Quality Gate

ลองเลือกสถานการณ์การทดสอบโค้ดและสภาพแวดล้อม เพื่อดูว่าระบบ Automated Quality Gate จะตรวจจับข้อผิดพลาดและปกป้อง Production ได้อย่างไร

ผลลัพธ์การประเมิน Quality Gate (CI/CD Pipeline Outcome):
• สปินอัป Ephemeral DB ➔ รัน Flyway ➔ pgTAP ตรวจสอบ 15 Tests ผ่านทั้งหมด ➔ Rollback ล้างข้อมูล 100%
• สถานะ Pipeline: ปลอดภัย อนุมัติ Merge Pull Request ได้ทันที
✅ Quality Gate Passed (5.2s)
2

💻 ปูพื้นฐานไวยากรณ์ & แบบฝึกหัดไต่ระดับ (pgTAP Unit Testing Mechanics)

การเขียน Database Unit Test ด้วย pgTAP ไม่ต่างจากการเขียน Unit Test ในภาษาอย่าง JUnit, Jest หรือ pytest แต่ทำในภาษา SQL ทั้งหมด โดยมีโครงสร้างหลัก 4 ส่วน: เริ่มด้วย BEGIN;, วางแผนด้วย plan(N);, ตรวจสอบด้วย Assertion Functions (เช่น is(), results_eq()), และจบด้วย ROLLBACK;:

🧱 แกะโครงสร้างไวยากรณ์: พิมพ์เขียวสคริปต์การทดสอบ pgTAP ใน PostgreSQL

พิมพ์เขียวสคริปต์: pgTAP Unit Testing Blueprint pgTAP SQL Structure
-- 🎯 [ส่วนที่ 1: Transaction Isolation & Extension Setup]
BEGIN;
CREATE EXTENSION IF NOT EXISTS pgtap;

-- 🎯 [ส่วนที่ 2: วางแผนจำนวนการทดสอบที่ต้องรัน]
SELECT plan(3); -- ระบุชัดเจนว่าต้องมี Assertion 3 ข้อ หากรันไม่ครบจะถือว่า Fail ทันที!

-- 🎯 [ส่วนที่ 3: Assertion Functions ตรวจสอบผลลัพธ์]
-- ข้อ 1: ตรวจสอบความถูกต้องของ Schema
SELECT has_table('accounts', 'ตาราง accounts ต้องมีอยู่ในระบบ');

-- ข้อ 2: ตรวจสอบค่าผลลัพธ์ของฟังก์ชัน (Actual vs Expected)
SELECT is(
    fn_calculate_discount(1000.00, 'GOLD'), -- Actual Value ที่ฟังก์ชันคำนวณได้
    150.00,                                 -- Expected Value ที่เราคาดหวัง
    'ส่วนลดระดับ GOLD สำหรับยอด 1,000 บาท ต้องเท่ากับ 150 บาท' -- คำอธิบาย Test Case
);

-- ข้อ 3: ตรวจสอบผลลัพธ์จาก Query ชุดข้อมูล
SELECT results_eq(
    'SELECT status FROM accounts WHERE account_id = 1', -- Actual Query
    'VALUES (''ACTIVE''::varchar)',                      -- Expected Query / Values
    'สถานะของบัญชีหมายเลข 1 ต้องเป็น ACTIVE'
);

-- 🎯 [ส่วนที่ 4: สรุปผลการทดสอบ และล้างข้อมูล 100%]
SELECT * FROM finish();
ROLLBACK; -- 💡 กฎเหล็ก: สั่ง ROLLBACK เสมอเพื่อไม่ให้มีข้อมูลทดสอบตกค้างในฐานข้อมูล!
💡 กฎเหล็กของ pgTAP: การใส่ SELECT * FROM finish(); และตามด้วย ROLLBACK; คือหัวใจของ Transactional Test Isolation ที่รับประกันว่าการทดสอบจะไม่มีผลกระทบต่อ State ของฐานข้อมูลเลยแม้แต่น้อย

🏋️‍♂️ แบบฝึกหัดไต่ระดับการเขียนจริง (จากระดับเริ่มต้น ➔ CI/CD Testcontainers Pipeline)

🟢 Level 1: การเขียน pgTAP ตรวจสอบ Schema Structure (has_table, has_column, has_function) ระดับเริ่มต้น
-- test/01_schema_test.sql
-- 🎯 ทดสอบความสมบูรณ์ของโครงสร้างตาราง คอลัมน์ และ Stored Units หลังรัน Flyway Migration
BEGIN;
CREATE EXTENSION IF NOT EXISTS pgtap;

SELECT plan(3);

-- [1] ตรวจสอบว่าตาราง orders ถูกสร้างขึ้นเรียบร้อยแล้วหรือไม่
SELECT has_table('orders', 'ตาราง orders ต้องถูกสร้างขึ้น');

-- [2] ตรวจสอบว่าคอลัมน์ net_amount มีอยู่ในตาราง orders หรือไม่
SELECT has_column('orders', 'net_amount', 'ตาราง orders ต้องมีคอลัมน์ net_amount');

-- [3] ตรวจสอบว่า Stored Procedure pr_transfer_funds_enterprise มีอยู่จริงหรือไม่
SELECT has_function('pr_transfer_funds_enterprise', 'ต้องมี Stored Procedure pr_transfer_funds_enterprise');

SELECT * FROM finish();
ROLLBACK;
จุดที่ต้องสังเกต: สคริปต์ Level 1 ใช้เวลาประมวลผลไม่ถึง 0.05 วินาที ช่วยตรวจจับปัญหาลืมสร้างคอลัมน์หรือสคริปต์ Migration รันตกหล่นได้อย่างแม่นยำ
🟡 Level 2: การทดสอบ Business Logic ของ Stored Function และ Trigger ด้วย is() และ results_eq() ระดับปานกลาง
-- test/02_business_logic_test.sql
-- 🎯 ทดสอบความถูกต้องของ Business Logic และ Transactional Changes
BEGIN;
CREATE EXTENSION IF NOT EXISTS pgtap;

SELECT plan(2);

-- [1] เตรียมข้อมูลจำลองสำหรับทดสอบ (Dummy Test Data) ใน Transaction
INSERT INTO accounts (account_id, account_no, balance, status)
VALUES (999, 'ACC-TEST-01', 5000.00, 'ACTIVE');

-- [2] Test 1: ทดสอบ Stored Function ดึงยอดเงินด้วย is()
SELECT is(
    fn_get_account_balance(999),
    5000.00,
    'ฟังก์ชัน fn_get_account_balance ต้องคืนค่ายอดเงิน 5000.00 ได้ถูกต้อง'
);

-- [3] Test 2: ทดสอบการทำงานของ Stored Procedure ฝากเงิน แล้วตรวจสอบผลลัพธ์ด้วย results_eq()
CALL pr_deposit_funds(999, 1500.00);

SELECT results_eq(
    'SELECT balance FROM accounts WHERE account_id = 999',
    'VALUES (6500.00::numeric)',
    'ยอดเงินหลังฝากเพิ่ม 1500 ต้องกลายเป็น 6500.00'
);

SELECT * FROM finish();
-- 🎯 [4] สั่ง ROLLBACK: ข้อมูลจำลอง ID 999 และประวัติเงินฝากจะถูกทำลายทิ้งทันที ไร้ Data Pollution!
ROLLBACK;
จุดที่ต้องสังเกต: คำสั่ง ROLLBACK; ตอนท้ายจะยกเลิกการ INSERT บัญชี 999 ทิ้งทั้งหมด ทำให้เราสามารถรันเทสต์นี้ซ้ำอีกพันครั้งโดยไม่เกิดปัญหาคีย์ซ้ำ (Duplicate Key Error)

🔴 Level 3: Refactoring CI/CD Database Testing Pipeline (เปรียบเทียบ Manual Shared DB vs Testcontainers + pgTAP)

เปรียบเทียบกระบวนการเดิมที่รัน Manual Test บน Shared Staging DB กับกระบวนการใหม่ที่ใช้ Testcontainers สปินอัป Ephemeral DB อัตโนมัติบน CI/CD Pipeline:

❌ กระบวนการเดิม: Manual Testing บน Shared Staging DB 3 วัน & ข้อมูลชนกันมหาศาล
# ❌ Flawed Process: ใช้ Staging DB ร่วมกันทั้งทีม
# 1. นักพัฒนาต่อ DBeaver เข้า staging-db.internal
# 2. แก้ข้อมูลในตารางทดสอบด้วยมือ ➔ คนอื่นรันเทสต์พังทันที (Data Pollution)
# 3. QA ต้องไล่คลิก Postman ทดสอบทีละ API นาน 3 วัน
# 4. ไม่มีการเช็ค Edge Cases เมื่อนำขึ้น Prod คำนวณเงินติดลบ เสียหาย 5 ล้านบาท!

# คำสั่งเดิมที่ใช้รัน:
psql -h staging-db.internal -U appuser -d staging_db -f test_script.sql
# ผลลัพธ์: ขยะข้อมูลตกค้างสะสมจนกลายเป็น Flaky Database!
วิเคราะห์ข้อเสีย: ขาดการแยกแยะสภาพแวดล้อม ข้อมูลทดสอบชนกันจนเกิด Flaky Tests และไม่สามารถผนวกเข้าสู่ระบบ CI/CD ได้จริง
✅ กระบวนการใหม่ระดับ Production: Testcontainers + pgTAP Pipeline 5 วินาที & Clean State 100%
# test_runner.py (สคริปต์รันอัตโนมัติบน GitHub Actions / GitLab CI)
# 🎯 สปินอัป Ephemeral PostgreSQL Container ชั่วคราว รัน Flyway แล้วยิง pgTAP
import os
from testcontainers.postgres import PostgresContainer
import psycopg2

# [Statement 1] สปินอัป Ephemeral Database Container สะอาดเอี่ยม 100%
with PostgresContainer("postgres:16-alpine") as postgres:
    db_url = postgres.get_connection_url()

    # [Statement 2] รัน Flyway Migration ปูโครงสร้าง Schema และ Stored Units
    print("🚀 Running Flyway Migrations on Ephemeral Container...")
    os.system(f"flyway -url={db_url} -user={postgres.username} -password={postgres.password} migrate")

    # [Statement 3] เชื่อมต่อและรัน pgTAP Automated Test Suite
    conn = psycopg2.connect(
        dbname=postgres.dbname,
        user=postgres.username,
        password=postgres.password,
        host=postgres.get_container_host_ip(),
        port=postgres.get_exposed_port(5432)
    )
    cur = conn.cursor()

    print("🧪 Executing pgTAP Automated Test Suite...")
    cur.execute(open("test/02_business_logic_test.sql", "r").read())
    results = cur.fetchall()

    for row in results:
        print(row)

    conn.close()
    # 🎯 เมื่อพ้นบล็อก with คอนเทนเนอร์ Docker จะถูกทำลายทิ้งทันที ไร้ขยะตกค้าง 100%!
วิเคราะห์ข้อได้เปรียบ: สภาพแวดล้อมสะอาด 100% ทุกครั้งที่รัน, ทำงานอัตโนมัติบน Pull Request ในเวลาเพียง 5 วินาที, และดักจับบั๊ก Business Logic ก่อนหลุดรอดสู่ Production ได้อย่างเด็ดขาด
3

📝 คลังข้อสอบและแบบประเมินความรู้ (18 ข้อ Multiple Choices พร้อมเฉลยยิบ)

แบบทดสอบวัดระดับความเข้าใจ Day 12: Automated Testing with Testcontainers & pgTAP (pgTAP Assertions, Ephemeral Database Containers, Transactional Test Isolation, Shift-Left Testing) และข้อสอบสะสมทบทวนครบทั้ง Days 1–11 คลิกเลือกคำตอบ ก, ข, ค, หรือ ง เพื่อดูผลลัพธ์และคำอธิบายอย่างละเอียดทันที

📊 สรุปผลการประเมิน Automated Database Testing (Day 12) 0 / 18
ความคืบหน้า ตอบแล้ว 0 จาก 18 ข้อ

🎉 ยินดีด้วยครับ! คุณได้ก้าวผ่านหมุดหมายสำคัญของ Pillar 03: Automated Quality Gate เรียบร้อยแล้ว

บทเรียน Day 12: Automated Testing with Testcontainers & pgTAP ได้เปลี่ยนผ่านกระบวนการตรวจสอบคุณภาพของ Stored Code จากการ Manual Test บน Shared Staging DB สู่กระบวนการ Shift-Left Automated Quality Gate บน CI/CD Pipeline อย่างสมบูรณ์แบบ การเขียน Unit Test ในภาษา SQL ด้วย pgTAP ร่วมกับการครอบด้วย BEGIN...ROLLBACK และการใช้ Testcontainers ช่วยให้คุณการันตีความถูกต้องของโค้ดฐานข้อมูลระดับล้านธุรกรรมได้อย่างมั่นใจ 100%

🚩 ก้าวต่อไปสู่ Day 13 (Decision Matrix - App vs. DB Boundaries & CPU Protection):

ในวันถัดไป เราจะไปเจาะลึกการกำหนดขอบเขตสถาปัตยกรรม (Architectural Boundaries) ระหว่าง Application Layer และ Database Layer ผ่าน Decision Matrix เพื่อตอบคำถามเชิงกลยุทธ์ว่า ตรรกะใดควรนำมาประมวลผล In-Database และตรรกะใดควรผลักออกไปรันบน App Layer เพื่อป้องกันปัญหา Database CPU Bottleneck ครับ!

เปิดบทเรียน Day 13 →