Code Coverage: วัดคุณภาพการทดสอบด้วย Code Coverage
ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการใช้ Data Providers เพื่อทดสอบฟังก์ชันด้วยชุดข้อมูลที่หลากหลาย ทำให้เรามั่นใจได้ว่าฟังก์ชันของเราทำงานได้อย่างถูกต้องในทุกกรณี ในบทนี้ เราจะมาทำความรู้จักกับเครื่องมือที่ช่วยให้เราวัดคุณภาพของการทดสอบได้ดียิ่งขึ้น นั่นคือ Code Coverage ครับ
Code Coverage คืออะไร?
Code Coverage คือ เมตริกที่ใช้วัดว่าโค้ดส่วนใดบ้างของโปรแกรมที่เราได้ทำการทดสอบไปแล้ว พูดง่ายๆ คือ มันจะบอกเราว่า test case ของเราครอบคลุมโค้ดของเรามากแค่ไหน หาก Code Coverage สูง แสดงว่า test case ของเราได้ทดสอบโค้ดส่วนใหญ่แล้ว แต่ถ้า Code Coverage ต่ำ แสดงว่ายังมีโค้ดอีกหลายส่วนที่เรายังไม่ได้ทดสอบ ซึ่งอาจมีความเสี่ยงที่จะเกิดข้อผิดพลาดได้
ลองนึกภาพว่าเรามีฟังก์ชันที่ซับซ้อน ซึ่งมีหลายเงื่อนไข (if/else statements) และ loop การทดสอบที่ดีจะต้องครอบคลุมทุกเงื่อนไขและทุก loop เพื่อให้มั่นใจว่าฟังก์ชันทำงานได้อย่างถูกต้องในทุกสถานการณ์ Code Coverage จะช่วยให้เราเห็นภาพรวมว่าเราได้ทดสอบครอบคลุมแค่ไหน และส่วนไหนที่ยังขาดอยู่
ทำไม Code Coverage ถึงสำคัญ?
- ช่วยระบุจุดที่ยังไม่ได้ทดสอบ: Code Coverage จะแสดงให้เห็นว่ามีโค้ดส่วนไหนบ้างที่ยังไม่มี test case ครอบคลุม ทำให้เราสามารถเขียน test case เพิ่มเติมเพื่อเพิ่มความครอบคลุม
- เพิ่มความมั่นใจในคุณภาพของโค้ด: เมื่อ Code Coverage สูง แสดงว่าโค้ดส่วนใหญ่ได้รับการทดสอบอย่างละเอียด ทำให้เรามั่นใจได้ว่าโค้ดมีคุณภาพดีและมีโอกาสเกิดข้อผิดพลาดน้อย
- ช่วยในการ Refactoring: เมื่อเราทำการปรับปรุงโค้ด (Refactoring) Code Coverage จะช่วยให้เรามั่นใจได้ว่าการเปลี่ยนแปลงของเราไม่ได้ทำให้เกิดข้อผิดพลาดใหม่ๆ
การวัด Code Coverage ด้วย PHPUnit
PHPUnit มีเครื่องมือที่ช่วยให้เราวัด Code Coverage ได้อย่างง่ายดาย โดยเราสามารถใช้คำสั่ง --coverage-html หรือ --coverage-clover เพื่อสร้างรายงาน Code Coverage ในรูปแบบ HTML หรือ XML ตามลำดับ
ตัวอย่างการใช้งาน:
สมมติว่าเรามีโปรเจกต์ PHP ที่มีโครงสร้างดังนี้:
my-project/
├── src/
│ └── Calculator.php
└── tests/
└── CalculatorTest.php
ไฟล์ src/Calculator.php มีโค้ดดังนี้:
<?php
namespace App;
class Calculator
{
public function add(int $a, int $b): int
{
if ($a > 100) {
return $a;
}
return $a + $b;
}
}
และไฟล์ tests/CalculatorTest.php มีโค้ดดังนี้:
<?php
namespace Tests;
use App\Calculator;
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase
{
public function testAdd()
{
$calculator = new Calculator();
$result = $calculator->add(2, 3);
$this->assertEquals(5, $result);
}
}
ในการวัด Code Coverage เราสามารถรันคำสั่ง PHPUnit ดังนี้:
./vendor/bin/phpunit --coverage-html coverage
คำสั่งนี้จะทำการรัน test case ทั้งหมด และสร้างรายงาน Code Coverage ในรูปแบบ HTML ภายใน directory ชื่อ coverage
การตีความผลลัพธ์ Code Coverage
หลังจากที่รันคำสั่ง PHPUnit พร้อมกับ option --coverage-html แล้ว เราจะได้ directory ที่มีไฟล์ HTML หลายไฟล์ ซึ่งเป็นรายงาน Code Coverage ของเรา ไฟล์ที่สำคัญที่สุดคือ index.html ซึ่งเป็นหน้าแรกของรายงาน
ในหน้าแรกของรายงาน เราจะเห็นภาพรวมของ Code Coverage ของทั้งโปรเจกต์ โดยจะแสดงเป็นเปอร์เซ็นต์ของ:
- Lines: จำนวนบรรทัดของโค้ดที่ถูกทดสอบ
- Statements: จำนวน statement (คำสั่ง) ที่ถูกทดสอบ
- Branches: จำนวน branch (ทางเลือก) ที่ถูกทดสอบ (เช่น if/else statements)
- Functions and Methods: จำนวนฟังก์ชันและเมธอดที่ถูกทดสอบ
- Classes and Traits: จำนวนคลาสและ trait ที่ถูกทดสอบ
หากเราคลิกที่ชื่อไฟล์ (เช่น Calculator.php) เราจะเห็นรายละเอียดของ Code Coverage สำหรับไฟล์นั้นๆ โดยจะมีการไฮไลท์โค้ดด้วยสีต่างๆ:
- สีเขียว: โค้ดส่วนนี้ถูกทดสอบแล้ว
- สีแดง: โค้ดส่วนนี้ยังไม่ได้ถูกทดสอบ
- สีเหลือง: โค้ดส่วนนี้ถูกทดสอบบางส่วน (เช่น branch ที่ไม่ได้ถูกทดสอบทั้งหมด)
จากตัวอย่างโค้ด Calculator.php และ CalculatorTest.php ข้างต้น จะเห็นว่า test case ของเราทดสอบเฉพาะกรณีที่ $a น้อยกว่าหรือเท่ากับ 100 เท่านั้น ดังนั้น โค้ดส่วนที่ $a > 100 จะถูกไฮไลท์เป็นสีแดงในรายงาน Code Coverage
ตัวอย่างรายงาน Code Coverage:
สมมติว่ารายงาน Code Coverage ของเราแสดงผลดังนี้:
Lines: 80.00% (8/10)
Statements: 75.00% (6/8)
Branches: 50.00% (1/2)
Functions: 100.00% (1/1)
Classes: 100.00% (1/1)
จากรายงานนี้ เราสามารถสรุปได้ว่า:
- 80% ของบรรทัดโค้ดถูกทดสอบแล้ว
- 75% ของ statement ถูกทดสอบแล้ว
- 50% ของ branch ถูกทดสอบแล้ว (แสดงว่ามีบางเงื่อนไขที่เรายังไม่ได้ทดสอบ)
- 100% ของฟังก์ชันและคลาสถูกทดสอบแล้ว
เพื่อให้ Code Coverage สูงขึ้น เราจะต้องเขียน test case เพิ่มเติมเพื่อครอบคลุมโค้ดส่วนที่ยังไม่ได้ทดสอบ ในกรณีนี้ เราจะต้องเขียน test case ที่ทดสอบกรณีที่ $a > 100 ด้วย
แก้ไข tests/CalculatorTest.php:
<?php
namespace Tests;
use App\Calculator;
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase
{
public function testAdd()
{
$calculator = new Calculator();
$result = $calculator->add(2, 3);
$this->assertEquals(5, $result);
}
public function testAddWhenAIsGreaterThan100()
{
$calculator = new Calculator();
$result = $calculator->add(101, 3);
$this->assertEquals(101, $result);
}
}
หลังจากเพิ่ม test case แล้ว ให้รันคำสั่ง PHPUnit อีกครั้ง:
./vendor/bin/phpunit --coverage-html coverage
รายงาน Code Coverage ควรจะแสดงผลเป็น:
Lines: 100.00% (10/10)
Statements: 100.00% (8/8)
Branches: 100.00% (2/2)
Functions: 100.00% (1/1)
Classes: 100.00% (1/1)
ซึ่งหมายความว่าเราได้ทดสอบโค้ดทั้งหมดแล้ว และ Code Coverage ของเราคือ 100%
ข้อควรระวังในการใช้ Code Coverage
ถึงแม้ว่า Code Coverage จะเป็นเครื่องมือที่มีประโยชน์ แต่ก็มีข้อควรระวังในการใช้งาน:
- Code Coverage สูงไม่ได้หมายความว่าโค้ดไม่มีข้อผิดพลาด: Code Coverage เพียงแค่บอกว่าโค้ดส่วนไหนถูกทดสอบแล้ว แต่ไม่ได้บอกว่า test case เหล่านั้นมีคุณภาพดีหรือไม่ เราอาจมี Code Coverage 100% แต่ test case ของเราอาจไม่ได้ครอบคลุมทุกกรณีที่เป็นไปได้
- อย่าให้ความสำคัญกับ Code Coverage มากเกินไป: การพยายามเพิ่ม Code Coverage ให้สูงโดยไม่คำนึงถึงคุณภาพของ test case อาจทำให้เราเสียเวลาไปกับการเขียน test case ที่ไม่มีประโยชน์ และอาจทำให้โค้ดของเราซับซ้อนขึ้น
- Code Coverage เป็นเพียงเครื่องมือช่วย: Code Coverage เป็นเพียงเครื่องมือที่ช่วยให้เราวัดคุณภาพของการทดสอบ แต่ไม่ได้เป็นตัวตัดสินว่าโค้ดของเรามีคุณภาพดีหรือไม่ การตัดสินใจว่าโค้ดของเรามีคุณภาพดีหรือไม่ ควรพิจารณาจากหลายปัจจัย เช่น ความสามารถในการอ่าน ความสามารถในการบำรุงรักษา และความสามารถในการแก้ไขปัญหา
สรุป
Code Coverage เป็นเครื่องมือที่มีประโยชน์ในการวัดคุณภาพของการทดสอบ ช่วยให้เราเห็นภาพรวมว่าเราได้ทดสอบโค้ดส่วนไหนบ้าง และส่วนไหนที่ยังขาดอยู่ การใช้ Code Coverage ร่วมกับการเขียน test case ที่มีคุณภาพ จะช่วยให้เรามั่นใจได้ว่าโค้ดของเรามีคุณภาพดีและมีโอกาสเกิดข้อผิดพลาดน้อย ในบทถัดไป เราจะมาเรียนรู้เกี่ยวกับเทคนิคการปรับปรุงโค้ดให้สะอาด (Clean Code) และอ่านง่าย ซึ่งเป็นสิ่งสำคัญในการพัฒนาซอฟต์แวร์ที่มีคุณภาพครับ