Wednesday, June 3, 2009

สร้างเทสเคสจากซอสโค้ดด้วยทฤษฎีกราฟ

ที่มา: http://www.kidkian.com/wordpress/tag/test-case/
  • เป็นบทความที่ค่อนข้างมีประโยชน์สำหรับตัวเอง
  • เก็บบันทึก log ตัวเองไว้ก่อนเลย

การทดสอบ (Test) โปรแกรมที่เราเขียนว่าทำงานได้อย่างถูกต้องหรือไม่นั้น ถือว่าเป็นขั้นตอนที่สำคัญขั้นตอนหนึ่งในการพัฒนาซอฟแวร์ (Software Development) การทดสอบโปรแกรมก็มีหลายระดับด้วยกันตั้งแต่ ทดสอบโปรแกรมย่อย (Unit Test) ไปจนถึงทดสอบระบบโดยรวมทั้งหมด (System Test)

ปกติ แล้วการทดสอบโปรแกรมแต่ละครั้งเราจะต้องเขียนสิ่งที่เราจะทดสอบและขั้นตอน การทดสอบอย่างละเอียดไว้ก่อนที่เราจะทดสอบโปรแกรม ซึ่งเราเรียกสิ่งนี้ว่า เทสเคส (Test Case) แล้วเทสเคสกับทฤษฎีกราฟ (Graph Theory) มาเกี่ยวกันได้ยังไงนั้น เรามาดูกัน

ซอสโค้ด = กราฟ

ซอสโค้ด (Source Code) ของโปรแกรมที่เราเขียนขึ้นนั้น เราสามารถที่จะเปลี่ยนคำสั่งต่างๆ ให้อยู่ในรูปของกราฟได้ โดยให้แต่ละคำสั่งเป็นโหนด (Node) ของกราฟและเส้นทางที่แต่ละคำสั่งถูกเรียกเป็นเส้นเชื่อมระหว่างโหนด (Edge) ดังรูปที่ 1

graph-detail
รูปที่ 1 องค์ประกอบของกราฟ

ลองมาดูตัวอย่างต่อไปนี้กัน ผมจะสร้างกราฟจากซอสโค้ดชุดหนึ่งซึ่งประกอบไปด้วย คำสั่งที่เป็นเงื่อนไขและคำนวนตัวเลขต่างๆ ดังนี้

if(score >= 80)
{
printf(”Grade A”);
}
else if((score => 60) && (score < 80))
{
printf(”Grade B”);
}
else
{
printf(”Grade C”);
}

จากซอสโค้ดข้างต้นเราจะเปลี่ยนแต่ละคำสั่งไปเป็นโหนด เราจะได้ 6 โหนดด้วยกันคือ

  1. score >= 80
  2. printf(”Grade A”)
  3. score => 60
  4. score <>
  5. printf(”Grade B”)
  6. printf(”Grade C”)

หลังจากที่เราได้โหนดแล้วเราก็มาสร้างเส้นเชื่อมแต่ละโหนดกัน โดยสร้างจากเส้นทาง (Path) ทั้งหมดที่เป็นไปได้ที่แต่ละคำสั่งจะถูกเรียก กราฟที่เราจะใช้หาเทสเคสจะต้องเป็นกราฟแบบมีทิศทาง ซึ่งจะได้ผลลัพธ์ดังรูปที่ 2

code-to-graph2
รูปที่ 2 กราฟผลลัพธ์

กราฟ = เทสเคส

ขั้นตอนต่อมาเราก็จะใช้กราฟที่ได้นั้นมาหาเทสเคสที่เป็นไปได้ทั้งหมด โดยการท่องไปแต่ละโหนดของกราฟ (Graph Traversing) แบบเชิงลึก (Depth-First Search) หลักการง่ายๆของการท่องกราฟแบบเชิงลึกก็คือ ถ้าเราพบว่าโหนดที่เรามาถึงมีเส้นเชื่อมต่ออยู่กับโหนดอื่นก็ให้ท่องไปยัง โหนดนั้นต่อ ทำอย่างนี้ไปเรื่อยๆ จนกระทั้งไม่มีโหนดให้เราท่องอีกต่อไป ถ้าโหนดนั้นมีเส้นเชื่อมมากกว่าหนึ่ง เราก็อาจจะไปทางขวาหรือทางซ้ายล่างสุดที่ต่อกับโหนดนั้นก่อนแล้วค่อยกลับมา ที่โหนดเดิมแล้วเริ่มท่องไปยังเส้นเชื่อมถัดไป

เราลองมาท่องกราฟใน รูปที่ 2 ดูกัน โดยไปทางขวาสุดก่อน เราจะพบว่ามีเส้นทางที่เป็นไปได้ 3 เส้นทางด้วยกัน ซึ่งแต่ละเส้นทางเท่ากับ 1 เทสเคสนั้นเอง

  1. (1) -> (2)
  2. (1) -> (3) -> (4) -> (5)
  3. (1) -> (3) -> (6)

จากเส้นทางที่ได้ทั้งหมดข้างต้นนั้น เราจะเห็นได้ว่ามีหลายเส้นทางที่มีลำดับของโหนดเหมือนกันบางส่วน เช่น (1) -> (3) ตรงส่วนที่เหมือนกันนี้จะเป็นประโยชน์ในเวลาที่เราเขียนสิ่งที่จะต้องทดสอบ ในแต่ละเทสเคส ช่วยลดความซ้ำซ้อนของสิ่งที่จะต้องทดสอบได้ สุดท้ายเราก็จะได้เทสเคสดังตัวอย่างตามตารางข้างล่างนี้

เทสเคสที่ เงื่อนไข ผลลัพธ์
1 score >= 80 พิมพ์ “Grade A”
2 score >= 60 และ score <> พิมพ์ “Grade B”
3 score <> พิมพ์ “Grade C”

การ ใช้กราฟในการหาเทสเคสนั้นอาจจะดูยุ่งยากในตอนแรก แต่ถ้าเราใช้จนชำนาญแล้วจะพบว่ามีประโยชน์มากๆ และทำให้เทสเคสทั้งหมดของเราครอบคลุมการทำงานที่เป็นไปได้ทั้งหมดของโปรแกรม ช่วยลดความผิดพลาดของโปรแกรมได้ดียิ่งขึ้นในเวลาที่ใช้งาน

ก่อนจบบทความนี้มีเรื่องที่ต้องเน้นไว้นิดหนึ่งว่า เวลาที่เราแปลงคำสั่งที่มีตัวดำเนินการทางตรรกะ (Logical Operator) เช่น && หรือ || มาเกี่ยวข้องนั้น จะทำให้ได้เส้นทางของกราฟต่างกัน เช่น ในซอสโค้ดตัวอย่างก่อนหน้านี้ถ้าเรา เปลี่ยนจาก (score >= 60) && (score <>= 60) || (score <>

code-to-graph-logical-opt
รูปที่ 3 กราฟผลลัพธ์เมื่อเปลี่ยนจาก && เป็น ||

ใน รูปที่ 3 เราจะเห็นเส้นประจากโหนดที่ 3 ไปยังโหนดที่ 6 ก็เพราะว่า || ทำให้เส้นทางไปยังโหนดที่ 6 หายไป เนื่องจากทุกๆ ค่าของ score จะทำให้เส้นทางไปสิ้นสุดที่โหนด 2 และ 5 เท่านั้น

No comments:

Post a Comment

Popular Posts