TIA ใน Pest 5 คืออะไร และวิธีรันเฉพาะ test ที่โค้ดที่เราแก้ไปถึง

TIA ใน Pest 5 จดไว้ว่า test แต่ละตัววิ่งผ่านไฟล์ไหน แล้วรอบต่อไปรันเฉพาะตัวที่ไฟล์นั้นเปลี่ยน โพสต์นี้มีตัวเลขจากโปรเจกต์ลูกค้าที่รอบเต็ม 201 วินาทีเหลือ 10 วินาที วิธีตั้ง pcov และจุดที่ทำให้ผลเขียวทั้งที่ไม่ได้รัน test

เผยแพร่
เวลาอ่าน
5 นาที
ในโพสต์นี้ 7 หัวข้อ
  1. Pest จดว่า test แต่ละตัววิ่งผ่านไฟล์ไหน
  2. ตัวเลขจากโปรเจกต์ลูกค้าที่ใช้ Pest 5
  3. ติดตั้ง pcov ไว้เป็น coverage driver
  4. ตั้ง composer script ไว้รันในเครื่อง
  5. บอก TIA ถึงไฟล์ที่มองไม่เห็นเอง
  6. ผลเขียวจาก TIA ไม่ได้แปลว่า test ผ่านทั้งชุด
  7. ให้ AI agent ใช้ TIA ระหว่างแก้โค้ด

ตอนที่ 3 ของซีรีส์ Testing ใน Laravel ต่อจากของใหม่ใน Pest 5

พอโปรเจกต์โตขึ้น test ก็ช้าลงตาม โปรเจกต์ลูกค้าที่ใช้ Pest 5 ตัวหนึ่งมี test ราวสองพันตัว รันทั้งชุดใช้ 201 วินาที ระหว่างแก้โค้ดเราแก้ class เดียวแล้วต้องรอสามนาทีกว่าจะรู้ว่าพังอะไรไหม สุดท้ายก็เลือกรันแค่ไฟล์ test ที่คิดว่าเกี่ยว แล้วไปเจอทีหลังใน CI ว่าพลาดไฟล์อื่น

TIA ให้ Pest เป็นคนเลือกแทนเรา

Pest จดว่า test แต่ละตัววิ่งผ่านไฟล์ไหน

รอบแรกที่ใส่ --tia Pest รันทั้งชุดโดยเปิด code coverage ไว้ coverage บอกได้ว่าระหว่าง test แต่ละตัวทำงาน PHP เข้าไปอ่านไฟล์ไหนบ้าง Pest เก็บความสัมพันธ์นี้ไว้เป็น graph พร้อม hash ของแต่ละไฟล์และผลของ test ทุกตัว

รอบต่อไป Pest ดูว่าไฟล์ไหนเปลี่ยนจาก git แล้วรันเฉพาะ test ที่วิ่งผ่านไฟล์นั้น ตัวที่เหลือไม่ได้รันจริง Pest เอาผลที่จำไว้มาแสดงแทน บรรทัดสรุปจึงมีคำใหม่สามคำ

  Tests:    774 passed (2658 assertions, 7 affected, 2 uncached, 765 replayed)
  Duration: 3.92s
  • affected รันใหม่เพราะไฟล์ที่ test ตัวนั้นใช้เปลี่ยน
  • uncached รันเพราะยังไม่มีผลเดิมเก็บไว้ เช่น test ที่เพิ่งเขียน
  • replayed ไม่ได้รัน ใช้ผลจากรอบก่อน

Pest ตัดช่องว่าง comment และ docblock ออกก่อนคิด hash แก้ comment หรือรัน Pint ทั้งโปรเจกต์จึงไม่ทำให้ test ตัวไหนต้องรันใหม่ ส่วนไฟล์ที่ไม่ใช่ PHP อย่าง migration, Blade และ component ของ Inertia ก็มีกฎของตัวเอง เช่น migration ที่เปลี่ยนจะรัน test ที่เคย query ตารางนั้น

ตัวเลขจากโปรเจกต์ลูกค้าที่ใช้ Pest 5

รอบ เวลา
รันเต็มแบบปกติ ไม่มี coverage 201 วินาที
รอบแรกของ TIA รันเต็มภายใต้ pcov 309 วินาที
ไม่ได้แก้อะไร 3.4 วินาที
แก้แค่ comment หรือจัด format 3.6 วินาที ไม่มี test ไหนรันจริง
แก้ class เดียวในโค้ดแอป 10.1 วินาที รัน 27 test จาก 6 ไฟล์
แก้ไฟล์ที่ทุก test โหลด เช่น routes/api.php รันเต็มทั้งชุด

รอบแรกช้ากว่าปกติราวครึ่งหนึ่ง เพราะ coverage ต้องคอยจดทุกบรรทัดที่ทำงาน แต่จ่ายครั้งเดียว หลังจากนั้นวงแก้โค้ดแล้วรัน test เหลือไม่กี่วินาที

แถวสุดท้ายก็ถูกต้องแล้ว ไฟล์ที่ทุก test ผ่าน TIA ช่วยอะไรไม่ได้ ไฟล์ config ก็เหมือนกัน แก้ config/app.php แล้ว Pest จะรันทั้งชุด เพราะพิสูจน์ไม่ได้ว่า test ไหนไม่เกี่ยว

ติดตั้ง pcov ไว้เป็น coverage driver

TIA ต้องมี coverage driver ตัวใดตัวหนึ่งระหว่าง pcov กับ Xdebug เราเลือก pcov เพราะทำแค่เก็บ coverage จึงเร็วกว่า Xdebug มาก

# Ubuntu หรือ Debian
sudo apt install php8.4-pcov

# macOS ที่ลง PHP ด้วย Homebrew
pecl install pcov

ถ้าใช้ Laragon หรือ XAMPP บน Windows แล้วเปิด Xdebug ไว้อยู่แล้ว ใช้ Xdebug ไปก่อนก็ได้ รอบแรกจะช้ากว่า

pcov มีเรื่องที่ต้องระวังสองเรื่อง

  • pcov ใช้กับ JIT ไม่ได้ PHP จะปิด JIT เองแล้วเตือนว่า JIT is incompatible with third party extensions… บน server จึงเปิด pcov เฉพาะ PHP CLI ไม่ใส่ให้ PHP-FPM ที่เสิร์ฟเว็บ ตั้ง pcov.enabled=0 ไว้เป็นค่าเริ่มต้น แล้วเปิดตอนรัน test ด้วย php -d pcov.enabled=1 ใส่ -d opcache.jit=disable ไปด้วยก็จะไม่เห็นคำเตือนนี้อีก
  • ถ้าโหลด pcov แต่ pcov.enabled=0 Pest ยังเลือก pcov เป็น driver แต่เก็บ coverage ไม่ได้สักบรรทัด graph ที่ได้จึงว่างเปล่าโดยไม่มี error

ตั้ง composer script ไว้รันในเครื่อง

โปรเจกต์ลูกค้าทั้งสองตัวตั้ง script นี้ไว้

"scripts": {
    "test:tia": [
        "@php artisan config:clear --ansi",
        "@php vendor/bin/pest --tia --locally --compact"
    ]
}

config:clear กันไม่ให้ config ที่ cache ไว้จากตอนพัฒนาไปปนกับค่าของ test ส่วน --locally บอก Pest ว่าเปิด TIA เฉพาะในเครื่องนักพัฒนา ถ้ารันใน CI ให้ข้ามไปรันเต็มชุดตามปกติ Pest รู้ว่ากำลังรันใน CI จาก environment variable อย่าง CI หรือ GITHUB_ACTIONS ที่ระบบ CI ตั้งไว้ให้

flag อื่นที่ใช้บ่อย

  • --fresh ทิ้ง graph เดิมแล้วจดใหม่ ใช้เมื่อสงสัยว่า graph ไม่ตรงกับโค้ดแล้ว
  • --no-tia ปิด TIA รอบเดียว
  • --baseline บอก path ที่เก็บ graph แล้วจบ ปกติอยู่ที่ ~/.pest/tia/ นอก repo จึงไม่ต้องเพิ่มอะไรใน .gitignore

บอก TIA ถึงไฟล์ที่มองไม่เห็นเอง

TIA รู้จักไฟล์จากสิ่งที่ coverage เห็น มีไฟล์สองแบบที่ coverage ไม่เห็น ในโปรเจกต์ลูกค้าเราจึงเพิ่มเองใน tests/Pest.php

pest()->tia()->watch([
    'database/snapshots/*.sql.gz' => 'tests',
    'tests/Pest.php' => 'tests',
]);
  • ไฟล์ snapshot ของฐานข้อมูล โปรเจกต์นี้โหลดตารางและข้อมูลตั้งต้นจากไฟล์ SQL ที่ commit ไว้ ไม่ได้รัน migration ทุกรอบ TIA รู้จักแค่ database/migrations ถ้าไม่บอก พอเราแก้ snapshot แล้ว TIA ก็จะเอาผลเดิมมาแสดงทั้งที่ฐานข้อมูลเปลี่ยนไปแล้ว วิธีจัดฐานข้อมูลแบบนี้อยู่ในตอนที่ 4
  • tests/Pest.php เอง Pest อ่านไฟล์นี้ก่อนเริ่มเก็บ coverage จึงไม่มี test ไหนผูกกับไฟล์นี้เลย ทั้งที่ในไฟล์มี base class, beforeEach และ helper ที่ทุก test ใช้

=> 'tests' แปลว่าไฟล์ที่ตรงกับ pattern เปลี่ยนเมื่อไร ให้รัน test ทั้งโฟลเดอร์ tests วิธีเช็กว่า pattern ใช้ได้จริงคือแก้ไฟล์นั้นแล้วดูบรรทัดสรุป ต้องเห็น affected ไม่ใช่ replayed

ผลเขียวจาก TIA ไม่ได้แปลว่า test ผ่านทั้งชุด

test ที่ขึ้นว่า replayed ไม่ได้รันในรอบนั้น ผลที่เห็นคือผลจากตอนที่ Pest จดไว้ ถ้า graph พลาดอะไรไป TIA ก็ไม่มีทางรู้ เราจึงใช้ TIA ระหว่างแก้โค้ดเท่านั้น ก่อน push รันทั้งชุดด้วย php artisan test อีกรอบ และ CI รันทั้งชุดทุกครั้งโดยไม่ใส่ --tia ตามที่เอกสารของ Pest แนะนำ

อีกสองกรณีที่ทำให้หลงคิดว่า TIA ทำงาน

  • ใส่ --tia แต่เครื่องไม่มี pcov หรือ Xdebug Pest ยังขึ้นข้อความว่าเปิดโหมด TIA แต่จดอะไรไม่ได้และรันทั้งชุดทุกครั้ง สังเกตจากบรรทัดสรุป ถ้าไม่มีคำว่า affected หรือ replayed แปลว่า TIA ไม่ได้ทำงาน
  • ใส่ --locally ใน workflow ของ CI ในโปรเจกต์ลูกค้าเราเคยลองเปิด TIA บน server ที่รัน test ก่อน deploy แล้วใส่ --locally ไว้ด้วย Pest ข้าม TIA ตามที่สั่ง แต่ pcov ยังเปิดอยู่ รอบนั้นจึงช้าที่สุด 688 วินาที เทียบกับราว 201 วินาทีตอนไม่มี pcov

ถ้าอยากให้ทั้งทีมไม่ต้องรอรอบแรกเอง Pest มี workflow ให้ CI จด graph ตอน merge เข้า main แล้วเครื่องนักพัฒนาดึงไปใช้ผ่าน gh ได้ รองรับ GitHub และ GitLab ตั้งแต่ Pest 5.2 แต่ต้องตั้ง workflow แยกอีกตัว ทีมเล็กใช้ --locally แล้วให้แต่ละเครื่องจดเองก็พอ

ให้ AI agent ใช้ TIA ระหว่างแก้โค้ด

TIA เหมาะกับงานที่ AI agent ทำมาก เพราะ agent แก้โค้ดแล้วรัน test วนหลายสิบรอบต่องาน ถ้ารอบละสามนาที งานชิ้นเดียวก็หมดไปเป็นชั่วโมง เขียนลำดับไว้ใน CLAUDE.md หรือ AGENTS.md ของโปรเจกต์ให้ชัด

## Tests

- ระหว่างแก้โค้ด รัน `composer test:tia` หลังแก้แต่ละครั้ง
- ก่อนบอกว่างานเสร็จ รัน `php artisan test --compact` ทั้งชุด แล้วรายงานผลจากรอบนั้น
- ผลเขียวจาก `test:tia` ไม่นับเป็นผลว่า test ผ่าน

บรรทัดสุดท้ายสำคัญที่สุด ถ้าไม่เขียนไว้ agent อาจเห็น TIA ขึ้นเขียวแล้วรายงานว่า test ผ่านหมด ทั้งที่รอบนั้น test เกือบทั้งหมดไม่ได้รันจริง

ตอนต่อไปเป็นเรื่องฐานข้อมูลสำหรับ test ที่เราใช้ snapshot กับ DatabaseTransactions แทน RefreshDatabase ถ้าเพิ่งเข้ามาที่ตอนนี้ รายชื่อทุกตอนอยู่ท้ายตอนแรกครับ

อ่านต่อ

ถูกอ้างถึงใน

ล่าสุด

ดูทั้งหมด →