ความซับซ้อนเชิงวัฏจักรในการทดสอบซอฟต์แวร์ พร้อมตัวอย่าง

⚡ สรุปอย่างชาญฉลาด

ความซับซ้อนเชิงวัฏจักร (Cyclomatic Complexity) เป็นตัวชี้วัดทางซอฟต์แวร์ที่พัฒนาโดย Thomas McCabe ในปี 1976 ซึ่งนับจำนวนเส้นทางอิสระในการทำงานของโปรแกรม โดยคำนวณจากกราฟการไหลของควบคุม และให้จำนวนกรณีทดสอบที่จำเป็นสำหรับการครอบคลุมสาขาอย่างสมบูรณ์

  • 📐 สองสูตร: V(G) = E – N + 2 จากกราฟ หรือ V(G) = P + 1 จากจำนวนจุดตัดสินใจ
  • 🧮 ความหมายโดยตรง: ค่านี้เท่ากับจำนวนเส้นทางอิสระสูงสุด และด้วยเหตุนี้จึงเท่ากับจำนวนกรณีทดสอบที่จำเป็น
  • 🗺️ ฐานกราฟ: จุด (nodes) แทนขั้นตอนการประมวลผล และเส้นเชื่อม (edges) แทนการไหลของการควบคุมระหว่างขั้นตอนเหล่านั้น
  • 🟢 1 ถึง 10: โค้ดที่มีโครงสร้างดี เขียนได้ดี ทดสอบได้ง่าย และมีต้นทุนการบำรุงรักษาต่ำ
  • 🟠 21 ถึง 40: โค้ดซับซ้อนมากและทดสอบได้ยาก โดยปกติแล้วการปรับปรุงโค้ดจะใช้ต้นทุนน้อยกว่าการทดสอบ
  • 🛠️ เครื่องมือ: SonarQube, Visual Studio Code โปรแกรม Metrics, Radon และ Lizard จะคำนวณค่านี้โดยอัตโนมัติ

ความซับซ้อนของไซโคลมาติกในการทดสอบซอฟต์แวร์

ความซับซ้อนของไซโคลมาติกของ McCabe คืออะไร?

ความซับซ้อนของไซโคลมาติกในการทดสอบซอฟต์แวร์ เป็นตัวชี้วัดการทดสอบที่ใช้ในการวัดความซับซ้อนของโปรแกรมซอฟต์แวร์ เป็นการวัดเชิงปริมาณของเส้นทางอิสระในโค้ดต้นฉบับของโปรแกรมซอฟต์แวร์ ความซับซ้อนแบบไซโคลมาติกสามารถคำนวณได้โดยใช้กราฟกระแสควบคุมหรือโดยคำนึงถึงฟังก์ชัน โมดูล วิธีการ หรือคลาสภายในโปรแกรมซอฟต์แวร์

เส้นทางอิสระถูกกำหนดให้เป็นเส้นทางที่มีขอบอย่างน้อยหนึ่งเส้นซึ่งไม่เคยถูกสำรวจมาก่อนในเส้นทางอื่น

ตัวชี้วัดนี้ได้รับการพัฒนาโดย Thomas J. McCabe ในปี 1976 และขึ้นอยู่กับการแสดงโฟลว์การควบคุมของโปรแกรม โฟลว์การควบคุมแสดงโปรแกรมเป็นกราฟซึ่งประกอบด้วยโหนดและขอบ

ในกราฟ โหนดแสดงถึงงานการประมวลผล ในขณะที่ขอบแสดงถึงโฟลว์การควบคุมระหว่างโหนด

ความซับซ้อนของไซโคลมาติกของแม็คเคบ

สัญกรณ์กราฟการไหลสำหรับโปรแกรม

สัญลักษณ์โฟลว์กราฟสำหรับโปรแกรมจะกำหนดโหนดต่างๆ ที่เชื่อมต่อผ่านขอบ ด้านล่างนี้คือไดอะแกรมโฟลว์สำหรับคำสั่งต่างๆ เช่น if-else, While, until และลำดับโฟลว์ปกติ

สัญลักษณ์โฟลว์กราฟสำหรับโปรแกรม

วิธีการคำนวณความซับซ้อนของไซโคลมาติก

การเป็นตัวแทนทางคณิตศาสตร์:

ในทางคณิตศาสตร์ มันคือเซตของเส้นทางอิสระที่ผ่านแผนภาพกราฟ Code ความซับซ้อนของโปรแกรมสามารถกำหนดได้โดยใช้สูตร –

V(G) = E - N + 2

ที่ไหน

E – จำนวนขอบ

N – จำนวนโหนด

V (G) = P + 1

โดยที่ P = จำนวนโหนดเพรดิเคต (โหนดที่มีเงื่อนไข)

ตัวอย่าง -

i = 0;
n=4; //N-Number of nodes present in the graph

while (i<n-1) do
j = i + 1;

while (j<n) do

if A[i]<A[j] then
swap(A[i], A[j]);

end do;
j=j+1;

end do;

Flow Graph ของโปรแกรมนี้จะเป็น

คำนวณความซับซ้อนของไซโคลมาติก

การคำนวณทางคณิตศาสตร์

  • วี(ก) = 9 – 7 + 2 = 4
  • V(G) = 3 + 1 = 4 (โหนดเงื่อนไขคือ 1,2 และ 3 โหนด)

ชุดฐานเส้นทางการดำเนินการอิสระทั้งสี่เส้นทาง:

  • 1, 7
  • 1, 2, 6, 1, 7
  • รถประจำทางสาย 1, 2, 3, 4, 5, 2, 6, 1, 7
  • 1, 2, 3, 5, 2, 6, 1, 7

คุณสมบัติของความซับซ้อนเชิงไซโคลมาติก

ต่อไปนี้เป็นคุณสมบัติของความซับซ้อนของไซโคลมาติก:

  1. V (G) คือจำนวนเส้นทางอิสระสูงสุดในกราฟ
  2. วี (ช) >=1
  3. G จะมีเส้นทางเดียวถ้า V (G) = 1
  4. แนวทางปฏิบัติที่ใช้กันทั่วไปคือการรักษาระดับ V(G) ให้อยู่ที่ 10 หรือต่ำกว่าสำหรับโมดูลเดียว

ตัวชี้วัดนี้มีประโยชน์อย่างไรต่อการทดสอบซอฟต์แวร์

การทดสอบ Basis Path เป็นหนึ่งในเทคนิค White box และรับประกันว่าจะมีการดำเนินการอย่างน้อยหนึ่งคำสั่งในระหว่างการทดสอบ โดยจะตรวจสอบแต่ละเส้นทางที่เป็นอิสระเชิงเส้นผ่านโปรแกรม ซึ่งหมายความว่า จำนวนกรณีทดสอบที่จำเป็นเท่ากับความซับซ้อนเชิงวัฏจักรของโปรแกรม.

เมตริกนี้มีประโยชน์เนื่องจากคุณสมบัติของความซับซ้อนของไซโคลมาติก (M) –

  1. M สามารถเป็นจำนวนกรณีทดสอบเพื่อให้ครอบคลุมสาขา (Upper Bound)
  2. M สามารถเป็นจำนวนเส้นทางผ่านกราฟได้ (ขอบเขตล่าง)

ลองพิจารณาตัวอย่างนี้ -

If (Condition 1)
Statement 1

Else
Statement 2

If (Condition 2)
Statement 3

Else
Statement 4

ความซับซ้อนของไซโคลมาติกสำหรับโปรแกรมนี้จะเป็น 8-7+2=3

เนื่องจากความซับซ้อนคำนวณไว้ที่ 3 จึงจำเป็นต้องมีกรณีทดสอบ XNUMX กรณีเพื่อให้ครอบคลุมเส้นทางทั้งหมดสำหรับตัวอย่างข้างต้น

ขั้นตอนที่ต้องปฏิบัติตาม

ควรปฏิบัติตามขั้นตอนต่อไปนี้สำหรับการคำนวณความซับซ้อนของ Cyclomatic และการออกแบบกรณีทดสอบ

ขั้นตอนที่ 1 – การสร้างกราฟด้วยโหนดและขอบจากโค้ด

ขั้นตอนที่ 2 – การระบุเส้นทางที่เป็นอิสระ

ขั้นตอนที่ 3 – การคำนวณความซับซ้อนของไซโคลมาติก

ขั้นตอนที่ 4 – การออกแบบกรณีทดสอบ

เมื่อสร้างชุดพื้นฐานแล้ว กรณีทดสอบ ควรเขียนเพื่อดำเนินการทุกเส้นทาง

ข้อมูลเพิ่มเติมเกี่ยวกับวี (G)

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

ตารางต่อไปนี้แสดงภาพรวมของหมายเลขความซับซ้อนและความหมายที่สอดคล้องกันของ v (G):

จำนวนความซับซ้อน ความหมาย
เพื่อ 1 10

โค้ดที่มีโครงสร้างและเขียนอย่างดี

ความสามารถในการทดสอบสูง

ต้นทุนและความพยายามน้อยลง

เพื่อ 11 20

รหัสที่ซับซ้อน

ความสามารถในการทดสอบปานกลาง

ค่าใช้จ่ายและความพยายามอยู่ในระดับปานกลาง

เพื่อ 21 40

โค้ดที่ซับซ้อนมาก

ความสามารถในการทดสอบต่ำ

ค่าใช้จ่ายและความพยายามสูง

> 40

ไม่สามารถทดสอบได้เลย

ต้นทุนและความพยายามสูงมาก

เครื่องมือสำหรับการคำนวณความซับซ้อนเชิงวัฏจักร

มีเครื่องมือมากมายสำหรับการกำหนดความซับซ้อนของแอปพลิเคชัน เครื่องมือคำนวณความซับซ้อนบางตัวใช้สำหรับเทคโนโลยีเฉพาะ ความซับซ้อนสามารถพบได้จากจำนวนจุดตัดสินใจในโปรแกรม จุดตัดสินใจได้แก่ คำสั่ง if, for, for-each, while, do, catch, case ในโค้ดต้นฉบับ

ตัวอย่างเครื่องมือได้แก่

  • โอคลินท์ – ตัววิเคราะห์โค้ดแบบคงที่สำหรับ C และภาษาที่เกี่ยวข้อง
  • SonarQube – รายงานความซับซ้อนทางด้านวัฏจักรและด้านการรับรู้ในกว่า 25 ภาษา
  • Visual Studio Code ตัวชี้วัด – การวิเคราะห์ความซับซ้อนเชิงวัฏจักรในตัวสำหรับแอสเซมบลี .NET
  • Radon และ Lizard – เครื่องมือวิเคราะห์ความซับซ้อนแบบบรรทัดคำสั่งสำหรับ Python และสำหรับโครงการหลายภาษาตามลำดับ
  • จีเมตริกส์ – ค้นหาตัวชี้วัดใน Java แอปพลิเคชันที่เกี่ยวข้อง

การใช้งานความซับซ้อนเชิงวัฏจักร

ความซับซ้อนของไซโคลมาติกอาจพิสูจน์ได้ว่ามีประโยชน์มากใน

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

วิธีการลดความซับซ้อนเชิงวัฏจักร

ตัวเลขความซับซ้อนสูงเป็นเพียงสัญญาณบ่งชี้ ไม่ใช่ข้อสรุป การปรับโครงสร้างใหม่สี่ครั้งนั้นคิดเป็นส่วนใหญ่ของการลดความซับซ้อนที่สามารถทำได้ในทางปฏิบัติ

  • Extracวิธี t การแยกสาขาออกไปอยู่ในฟังก์ชันของตัวเองจะแบ่งความซับซ้อนออกเป็นสองโมดูล ความซับซ้อนโดยรวมของระบบยังคงไม่เปลี่ยนแปลง แต่แต่ละหน่วยจะสามารถทดสอบได้อย่างอิสระ
  • แทนที่การเชื่อมโยงเงื่อนไขด้วยการค้นหาข้อมูล โครงสร้างเงื่อนไข if-else-if ที่ยาวเหยียดซึ่งทดสอบตัวแปรเดียวกัน จะกลายเป็นแผนผังหรือสวิตช์ ซึ่งช่วยลดจุดตัดสินใจหลายจุดให้เหลือเพียงจุดเดียว
  • ใช้เงื่อนไขป้องกัน (guard clause) การคืนค่ากลับทันทีเมื่อได้รับข้อมูลที่ไม่ถูกต้องจะช่วยขจัดความซับซ้อนของคำสั่ง if-else ขนาดใหญ่เพียงคำสั่งเดียว โดยไม่เปลี่ยนแปลงพฤติกรรม
  • แทนที่เงื่อนไขด้วยโพลีมอร์ฟิซึม ในกรณีที่เงื่อนไขขึ้นอยู่กับประเภท การย้ายแต่ละสาขาไปอยู่ในคลาสของตัวเองจะช่วยขจัดความจำเป็นในการตัดสินใจออกไปโดยสิ้นเชิง

ก่อนหน้านี้ เมื่อ V(G) = 4:

if (user != null) {
    if (user.isActive()) {
        if (user.hasRole("admin")) {
            return grantAccess();
        }
    }
}
return denyAccess();

หลังจากนั้น โดยที่พฤติกรรมยังคงเหมือนเดิม แต่ได้เอาส่วนที่เป็นรังออกไปแล้ว:

if (user == null) return denyAccess();
if (!user.isActive()) return denyAccess();
if (!user.hasRole("admin")) return denyAccess();
return grantAccess();

ข้อควรระวังเกี่ยวกับตัวชี้วัดนี้ ความซับซ้อนเชิงวัฏจักรนับจำนวนการตัดสินใจ ไม่ใช่ความยาก คำสั่ง switch ที่มี 20 กรณีง่ายๆ ได้คะแนน 21 แต่ก็ยังอ่านง่าย ในขณะที่บล็อกซ้อนกันหลายชั้นได้คะแนน 8 อาจเข้าใจยากกว่ามาก ควรใช้ตัวเลขนี้เพื่อค้นหาตัวอย่างที่ควรตรวจสอบ ไม่ใช่ใช้เป็นเป้าหมายในการโกงคะแนน

คำถามที่พบบ่อย

โดยทั่วไปแล้ว จำนวนโมดูลไม่เกิน 10 โมดูลถือเป็นหลักเกณฑ์สำคัญ หากมี 11 ถึง 20 โมดูล โค้ดจะซับซ้อนแต่ยังพอจัดการได้ หากเกิน 20 โมดูล ความสามารถในการทดสอบจะลดลงอย่างมาก และหากเกิน 40 โมดูลนั้นโดยทั่วไปจะถือว่าทดสอบไม่ได้แล้ว

ทั้งสองวิธีให้ผลลัพธ์เหมือนกัน วิธี P + 1 เร็วกว่าสำหรับการคำนวณด้วยมือ เพราะนับเฉพาะจุดตัดสินใจเท่านั้น ส่วนวิธี E – N + 2 เป็นวิธีที่เครื่องมือใช้ เนื่องจากเครื่องมือเหล่านั้นสร้างกราฟควบคุมการไหลไว้แล้ว

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

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

ใช่แล้ว ผู้ช่วย AI จะเสนอเงื่อนไขป้องกัน เช่นtracใช้เมธอด ted และตารางค้นหาที่ช่วยลดจำนวนลง ตรวจสอบพฤติกรรมด้วยชุดทดสอบที่มีอยู่ เนื่องจากการปรับโครงสร้างใหม่ที่เปลี่ยนแปลงตรรกะจะทำให้จุดประสงค์เสียไป

สรุปโพสต์นี้ด้วย: