1 คะแนน โดย GN⁺ 5 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เมื่อพยายามหาว่าส่วนใดของอินพุตขนาดใหญ่ที่ทำให้เกิดปัญหา ตัวลดขนาดเคสทดสอบ จะช่วยย่ออินพุตให้อัตโนมัติเพื่อให้ดีบักได้ง่ายขึ้น
  • ตัวลดขนาดจะรับโปรแกรม อินพุต และ การทดสอบความน่าสนใจ แล้วตรวจซ้ำว่าข้อมูลนำเข้าตัวเลือกที่สั้นลงยังสร้างปัญหาเดิมได้หรือไม่
  • แม้แต่ตัวลดขนาดแบบลบบรรทัดอย่างง่ายก็ยังสามารถเหลือคำยาวคำเดียวจาก /usr/share/dict/words ได้ และในตัวอย่าง C ก็ลดจาก 78 บรรทัดเหลือ 54 บรรทัดได้ในเวลาไม่ถึง 10 วินาที
  • การทดสอบความน่าสนใจต้องเขียนให้แม่นยำและรวดเร็ว เพราะมีปัจจัยอย่างการย่อเกินจำเป็น การรันช้า การรันไม่จบ และสภาพแวดล้อมการรันแบบขนาน
  • นอกจากความยาวอินพุตแล้ว หากใส่ตัวชี้วัดอย่างความถี่ในการเกิดข้อผิดพลาดหรือความยาวของร่องรอยการทำงานลงใน การทดสอบความน่าสนใจ ก็จะช่วยดีบัก บั๊กแบบไม่กำหนดแน่นอน และล็อกร่องรอยขนาดใหญ่ได้

การย่อเคสทดสอบ

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

โครงสร้างพื้นฐานของตัวลดขนาดเคสทดสอบ

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

    • โปรแกรมตัวอย่างจะอ่านบรรทัดจากไฟล์ และถ้ามีบรรทัดใดยาวเกิน 25 อักขระ จะพิมพ์ Word too long
    • การทดสอบความน่าสนใจจะคืนค่า 0 หากเอาต์พุตของโปรแกรมมี Word too long และคืนค่า 1 หากไม่มี
    • ตัวลดขนาด Python แบบง่ายจะอ่านอินพุตทีละบรรทัด เขียนอินพุตตัวเลือกที่ลบบรรทัดหนึ่งออกลงไฟล์ชั่วคราว แล้วรันการทดสอบความน่าสนใจ
    • หากอินพุตตัวเลือกยังน่าสนใจ ก็จะเปลี่ยนอินพุตปัจจุบันเป็นตัวเลือกนั้น และถ้าลดต่อไม่ได้แล้วก็พิมพ์ผลลัพธ์ไปที่ stdout
    • เมื่อนำไปรันกับ /usr/share/dict/words ผลลัพธ์จะเหลือเพียง antidisestablishmentarianism

ตัวลดขนาดที่ทรงพลังกว่าและ Shrink Ray

  • ตัวอย่างโปรแกรม C 78 บรรทัดเกี่ยวข้องกับปัญหาที่ให้ผลลัพธ์ต่างกันระหว่างการตั้งค่า FAST=0 และ FAST=1
  • การทดสอบความน่าสนใจจะคอมไพล์ด้วยทั้งสองการตั้งค่า แล้วผ่านก็ต่อเมื่อเอาต์พุตของ FAST=0 เป็น 0d754a56 และเอาต์พุตของ FAST=1 ต่างจากค่านั้น
  • ตัวลดขนาดอย่างง่ายสามารถลดอินพุต C 78 บรรทัดให้เหลือ 54 บรรทัดได้ในเวลาไม่ถึง 10 วินาที คิดเป็นการย่อประมาณ 30% ตามจำนวนบรรทัด
  • หากเพิ่ม i=0 เพื่อให้กลับไปเริ่มลบจากบรรทัดแรกใหม่ทุกครั้งที่พบอินพุตตัวเลือกที่น่าสนใจ เวลารันจะเพิ่มขึ้นเกือบ 10 เท่า แต่ลดได้เพิ่มอีก 3 บรรทัด
  • Shrink Ray มีทั้งกฎการย่อหลายแบบและการรันแบบขนาน และถ้าใส่ --no-clang-delta ก็จะไม่ใช้ความรู้เฉพาะทางเกี่ยวกับ C
  • Shrink Ray ใช้เวลาราว 15 นาทีเพื่อลดอินพุตลงมากกว่า 60% ตามขนาดไบต์ และในอีกกรณีหนึ่งพบการย่อราว 90% หลังประมาณ 20 นาที ก่อนจะลดต่อไปจนถึง 99%
  • Shrink Ray รู้จักไวยากรณ์คอมเมนต์มาตรฐานและพยายามลบส่วนนั้นก่อนตั้งแต่ต้น รวมถึงพยายามลดจำนวนเต็มให้เป็นค่าที่เล็กลงด้วย

ความยากในการเขียนการทดสอบความน่าสนใจ

  • ตัวลดขนาดเคสทดสอบจะทำตามการทดสอบความน่าสนใจแบบตรงตัว ดังนั้นถ้าการทดสอบผ่านอย่างผิดพลาด ก็อาจเกิด การย่อเกินจำเป็น ที่ลดเลยจุดที่เราต้องการ
  • Shrink Ray จะตรวจอย่างชัดเจนว่าการทดสอบความน่าสนใจยอมรับอินพุตว่างหรือไม่ และสถานการณ์แบบนี้เกิดขึ้นได้บ่อย
  • ในตัวอย่าง C หากตรวจแค่ว่าเอาต์พุตทั้งสองต่างกันหรือไม่ ก็อาจจัดให้ความแตกต่างของเอาต์พุตที่ไม่สำคัญหรือชวนให้เข้าใจผิดเป็นอินพุตที่น่าสนใจได้
  • การตรวจ test "$slow_out" = "0d754a56" ช่วยยืนยันว่าเวอร์ชันช้าทำงานตามที่คาดจริง จึงลดโอกาสการย่อเกินจำเป็น
  • ความเร็วและการตั้งเวลา timeout

    • หากการทดสอบความน่าสนใจเร็ว ตัวลดขนาดอาจรันได้หลายร้อยครั้งต่อวินาที
    • แม้แต่ตัวอย่างขนาดกลางก็อาจนำไปสู่ความพยายามย่อหลายแสนครั้ง ดังนั้นการปรับแต่งการทดสอบความน่าสนใจจึงมีผลมากต่อเวลารวม
    • มีกรณีที่ทำให้การทดสอบความน่าสนใจเร็วขึ้นราว 3 เท่าโดยปิดการสร้าง core dump อัตโนมัติ
    • ตัวลดขนาดอาจลบบรรทัดอย่าง i-=1 แล้วทำให้โปรแกรมที่เคยจบการทำงานได้ กลายเป็นโปรแกรมที่รันไม่สิ้นสุด
    • ถ้าโปรแกรมใช้เวลา 0.1 วินาทีต่อการรัน แต่ตั้ง timeout ไว้ 60 วินาที การย่อทั้งกระบวนการจะช้าลงมาก
    • สำหรับโปรแกรมที่เร็ว มักตั้ง timeout แบบปัดขึ้นเป็น 1~2 วินาที ส่วนกรณีอื่นมักใช้ราว 1.5~2 เท่าของเวลาเริ่มต้นในการรัน
  • การรันแบบขนาน

    • ตัวลดขนาดอย่าง Shrink Ray จะรันการทดสอบความน่าสนใจแบบขนาน
    • Shrink Ray จะรันการทดสอบความน่าสนใจแต่ละครั้งในไดเรกทอรีชั่วคราว และล้างไดเรกทอรีนั้นให้อัตโนมัติ
    • บางกรณีไดเรกทอรีชั่วคราวอย่างเดียวก็ยังไม่พอ และมาตรการที่ต้องใช้จะแตกต่างกันไปในแต่ละกรณี

ทำให้เกิดความเป็นกำหนดแน่นอนด้วยการทดสอบความน่าสนใจ

  • โค้ดตัวอย่างสร้างข้อผิดพลาดหารด้วยศูนย์เพราะ len([])==0 แต่เนื่องจากมีเงื่อนไข random.random() < 0.33 ปัญหาจึงเกิดขึ้นเพียงประมาณหนึ่งในสามของการรัน
  • บั๊กแบบไม่กำหนดแน่นอนทำให้ข้อผิดพลาดปรากฏและหายไปแบบสุ่ม ส่งผลให้การตรวจสอบสมมติฐานยากขึ้นและใช้เวลานานขึ้น
  • หากตัวลดขนาดลบการเรียก random.random() ออก หรือเปลี่ยนนิพจน์เงื่อนไข บั๊กที่ไม่กำหนดแน่นอนก็อาจกลายเป็นบั๊กที่เกิดซ้ำได้แน่นอน
  • ความไม่กำหนดแน่นอนในโลกจริงมักมาจากหลายส่วนของอินพุตโต้ตอบกันในทางไม่พึงประสงค์ จึงอาจกำจัดออกได้ยาก
  • ตัวลดขนาดเคสทดสอบทำงานคล้ายอัลกอริทึมไต่เขาที่ใช้ความยาวอินพุตเป็นตัวชี้วัดแทนว่าอะไร “ดีกว่า”
  • แนวทางแบบไต่เขามักติดอยู่ที่จุดเหมาะสมเฉพาะที่ และอินพุตที่สั้นกว่าก็ไม่ได้แปลว่าจะดีกว่าสำหรับการค้นหาบั๊กเสมอไป
  • วิธีรันซ้ำหลายครั้ง

    • เมื่อต้องจัดการกับบั๊กแบบไม่กำหนดแน่นอน มักใช้การทดสอบความน่าสนใจที่รันอินพุตเดียวกันหลายครั้ง และยอมรับอินพุตนั้นหากข้อผิดพลาดที่สนใจเกิดขึ้นอย่างน้อยหนึ่งครั้ง
    • วิธีนี้อาจช่วยเพิ่มความถี่ในการเกิดข้อผิดพลาดได้
    • แต่การทดสอบที่ผ่านเมื่อเกิดเพียงครั้งเดียวจะยังยอมรับอินพุตแบบไม่กำหนดแน่นอน จึงอาจทำให้ระหว่างการย่อ ความไม่กำหนดแน่นอนเพิ่มขึ้นแทน
    • วิธีที่เข้มงวดกว่าคือทดสอบให้ผ่านเฉพาะเมื่อข้อผิดพลาดเกิดขึ้นครบทุกครั้งจากการรันซ้ำ n ครั้ง
    • การทดสอบที่เข้มงวดทำให้ความน่าจะเป็นที่อินพุตเริ่มต้นจะผ่านต่ำ จึงเริ่มใช้ Shrink Ray ได้ยาก และในตัวอย่างที่กำหนดให้รันซ้ำ 3 ครั้ง ความน่าจะเป็นเริ่มต้นที่จะผ่านมีเพียง 3.6%
    • วิธีเลี่ยงที่ใช้งานได้จริงคือเริ่มจากการทดสอบแบบ “เกิดข้อผิดพลาดอย่างน้อย 1 ครั้งจาก n ครั้ง” ก่อน แล้วเมื่อได้อินพุตที่ย่อแล้วซึ่งทำให้ข้อผิดพลาดเกิดบ่อยขึ้น ค่อยเปลี่ยนเป็น “เกิดข้อผิดพลาดต่อเนื่อง n ครั้ง”

ตัวนับแบบโกลบอลและตัวชี้วัดเป้าหมายอื่น ๆ

  • การแทรกแซงด้วยมือนั้นทรงพลัง แต่ต้องคอยเฝ้า Shrink Ray และพลาดจังหวะแทรกแซงได้ง่าย
  • หากต้องการชี้นำตัวลดขนาดด้วยคุณสมบัติอื่นที่ไม่ใช่ความยาวอินพุต ก็สามารถบังคับคุณสมบัตินั้นไว้ภายในการทดสอบความน่าสนใจเดียวได้
  • ในการดีบัก yk สิ่งที่สำคัญกว่าความยาวอินพุตคือความยาวของร่องรอยการทำงาน หรือค่าที่ใกล้เคียงกับจำนวนคำสั่งที่โปรแกรมรัน
  • เอาต์พุต YKD_LOG="$t:jit-asm" จะเขียนทั้ง trace IR แบบข้อความและคำสั่งภาษาเครื่องลงไฟล์ และเอาต์พุต jit-asm ที่สั้นกว่าจะทำให้ดีบักง่ายขึ้น
  • wc -l ใช้นับจำนวนบรรทัดของไฟล์ล็อก เพื่อเป็นตัวชี้วัดแทนที่ใกล้เคียงกับความยาวของร่องรอย
  • การทดสอบความน่าสนใจจะถือว่าอินพุตไม่น่าสนใจ หากจำนวนบรรทัดของร่องรอยปัจจุบันมากกว่าค่าต่ำสุดก่อนหน้า โดยเก็บค่าต่ำสุดไว้ที่ /tmp/global_best
  • วิธีนี้ไม่ปลอดภัยสำหรับการย่อแบบขนาน และมีสมมติฐานบางอย่างเกี่ยวกับวิธีที่ตัวลดขนาดเรียกใช้งาน แต่สำหรับสคริปต์สั้น ๆ ที่เขียนใช้แล้วทิ้งก็ถือเป็นความไม่สมบูรณ์ที่ยอมรับได้
  • ในกรณี segfault ของ yk การย่อแบบทั่วไปยังคงเหลือร่องรอย 40K บรรทัด แต่เทคนิคนี้ให้ร่องรอย 10.1K บรรทัดแทนอินพุตที่ใหญ่กว่าซึ่งถูกย่อ และช่วยให้หาบั๊กรากเหง้าได้ภายใน 30 นาที

สรุปประเด็นสำคัญ

  • ตัวลดขนาดเคสทดสอบไม่ใช่เครื่องมือที่มีประโยชน์เฉพาะสำหรับผู้เขียนคอมไพเลอร์เท่านั้น แต่ยังใช้กับปัญหาที่ไม่ใช่คอมไพเลอร์ได้ด้วย
  • นอกจากเป้าหมายพื้นฐานอย่างการลดความยาวอินพุตแล้ว ยังสามารถชี้นำด้วยการทดสอบความน่าสนใจให้มุ่งไปที่คุณสมบัติอย่างความถี่ของข้อผิดพลาด เวลาแบบ wall-clock ระดับความไม่กำหนดแน่นอน หรือความยาวของร่องรอยได้
  • ความแม่นยำ ความเร็ว เวลา timeout และความปลอดภัยในการรันแบบขนานของการทดสอบความน่าสนใจ เป็นตัวกำหนดประสิทธิผลจริงของตัวลดขนาด
  • แม้ตัวลดขนาดแทบไม่เข้าใจความหมายของอินพุตและโปรแกรม แต่ก็ยังช่วยคงปัญหาไว้ในรูปที่เล็กลง และเพิ่มประสิทธิภาพการดีบักได้

1 ความคิดเห็น

 
GN⁺ 5 시간 전
ความคิดเห็นจาก Lobste.rs
  • สงสัยจริง ๆ ว่ามีใครบ้างที่ไม่เห็นคุณค่าของ การย่อ test case อัตโนมัติ? คำว่า “ถูกประเมินต่ำไป” ฟังเหมือนมีคนที่ไม่ต้องการการย่อ test case อยู่เสมอ
    ต่อให้ระบุบั๊กได้ทันที ก็ยังต้องมีเคสที่ย่อแล้วไว้ใช้เป็น regression test ไม่ใช่หรือ?

    • ปกตินักพัฒนาคงไม่เคยคิดว่านี่เป็น เทคนิค ด้วยซ้ำ
    • บรรทัดแรกของบทความเขียนว่า “Test-case reducers are less well known than they should be, [...]” ซึ่งจากมุมของคนที่แนะนำให้คนอื่นใช้ fuzzing และการทดสอบเชิงคุณสมบัติมาหลายปี ก็รู้สึกแบบนั้นเหมือนกัน
      ทั้งสองอย่างมักรวมการย่อเคสล้มเหลวหรือ “shrinking” เอาไว้ในรูปแบบใดรูปแบบหนึ่ง และนั่นทำให้ใช้งานได้จริงมากขึ้นมาก
    • ในโลกของ fuzzer พอรู้เรื่องนี้อยู่บ้าง หลังจาก fuzzer หาเคสที่ล้มเหลวได้แล้ว มันจะย่อให้เองอัตโนมัติ และส่วนนั้นทำงานได้ดีมาก
      แต่จากประสบการณ์ที่ใช้ fuzzing โดยรวม โดยเฉพาะ AmericanFuzzyLop และ AFL++ การตั้งค่ามันทรมานเกินไปจนมักจะเลี่ยง
      บั๊กส่วนใหญ่ที่ผมเจอก็ไม่ได้เป็นแนว “ใส่ไฟล์อินพุตนี้แล้วจะทำงานผิด” แต่จะใกล้กับ “มีผู้ใช้บางคนที่ไหนสักแห่งเจอการทำงานผิด” มากกว่า บางครั้งพอลดรูปได้ถึงระดับ “ถ้าทำตามขั้นตอนชุดหนึ่งภายใต้เงื่อนไขเฉพาะแล้วจะพัง” แต่ 1) ไม่ค่อยรู้ว่าจะเอาตัวลด test case อัตโนมัติมาใช้กับ “ผู้ใช้ทำอะไรตามลำดับ” ยังไง และ 2) พอหาวิธีทำให้เกิดซ้ำบนเครื่องตัวเองได้ การดีบักก็ถือว่าเสร็จไป 99% แล้ว
      ผู้เขียนคงมองท่าทีแบบนี้ของผมว่าเป็นการ “ประเมินต่ำไป”
    • คนที่รู้ด้วยซ้ำว่า การย่อ test case คืออะไร น่าจะมีไม่มาก
  • แม้บทความและตัวอย่างนี้จะบอกว่าตัวลดเคสควรถูกใช้ให้แพร่หลายขึ้นในบริบทที่ไม่ใช่คอมไพเลอร์ด้วย แต่มุมมองก็ยังเอนเอียงไปทาง ผู้เขียนคอมไพเลอร์ มากพอสมควร
    อย่างที่ ~silentbicycle เขียนไว้ การย่อ test case ส่วนใหญ่เกิดขึ้นในบริบทของ fuzzer หรือการทดสอบเชิงคุณสมบัติ และความสามารถในการย่อมักฝังมาในเฟรมเวิร์กที่ใหญ่กว่าอยู่แล้ว คอมไพเลอร์เป็นหนึ่งในโดเมนพิเศษที่ตัวย่อ test case แบบแยกเดี่ยวมีประโยชน์ ผมก็ไม่แน่ใจว่ามีกรณีอื่นอีกไหมที่ตัวย่อแบบแยกเดี่ยวจะช่วยได้
    ประเด็นเรื่อง ความกำหนดแน่นอน ก็น่าสนใจ ตัวอย่างเริ่มจากไฟล์อินพุตที่ก่อบั๊ก คือสคริปต์ ซึ่งทำให้เกิดความกำหนดแน่นอน ไม่ใช่จากตัวโปรแกรมที่มีบั๊กอย่างอินเทอร์พรีเตอร์เอง บทความไม่ได้ชัดเจนนักว่าหมายถึงเทคนิค “interestingness” ใช้ได้กับสถานการณ์ที่ไม่ใช่คอมไพเลอร์ซึ่งตัวโปรแกรมที่มีบั๊กเองก็ไม่กำหนดแน่นอนด้วยหรือไม่
    วิธีหนึ่งในการปรับปัญหาการทดสอบให้เข้ากับ fuzzing และการย่อ test case คือแนะนำให้สร้างชุดคำสั่งเชิงคำสั่งที่มีหมายเลขกำกับ แต่ละคำสั่งใส่การตรวจสอบความสอดคล้องแบบเบา ๆ เพื่อจับความล้มเหลวของการทดสอบ รวมถึงกรณีที่ไม่ crash ทันที ส่วนการตรวจสอบที่หนักกว่าควรแยกเป็นอีกคำสั่งหนึ่งเพื่อลดผลกระทบต่อความเร็วการทดสอบ ในการทดสอบแบบสุ่มง่าย ๆ ก็ให้ test harness สุ่มเลือกคำสั่งไปเรื่อย ๆ จนกว่าจะมีอะไรพัง แล้วตอนเปลี่ยนไปใช้ harness ของ fuzzer ก็ให้ใช้สตรีมไบต์อินพุตจากการ fuzz เพื่อเลือกคำสั่ง เท่านี้ก็จะได้ของดีอย่าง regression test ที่กำหนดแน่นอนและการย่อ test case แบบอัตโนมัติ
    ผมไม่เคยได้ผลอะไรมากนักจากการสั่ง libfuzzer ให้ย่อ test case อย่างชัดเจน น่าจะเพราะมันย่อไปแล้วระหว่างสร้างอินพุตอยู่ก่อนแล้ว เลยไม่ค่อยมีแรงจูงใจจะลองเพิ่มการตรวจ interestingness สำหรับการย่อเคสด้วย fuzzer ทั่วไปมากกว่านี้ สงสัยเหมือนกันว่าคนอื่นเคยทำสำเร็จไหม

    • เห็นด้วยเต็มที่ ผมใช้วิธีนี้บ่อย สร้างตัวแทนเชิงสัญลักษณ์ของ อินเทอร์เฟซที่มีสถานะ จากนั้นก็มักทำอินเทอร์พรีเตอร์ง่าย ๆ ด้วย switch-case หรือ match แล้วสุ่มสร้างรายการการดำเนินการมารัน และย่ออินพุตที่ทำให้เกิด assert จากการละเมิดเงื่อนไขก่อน/หลัง หรือจากความเสียหายภายใน
      จะเรียกมันว่าการทดสอบเชิงคุณสมบัติ, fuzzing หรือ model checking แบบเบา ๆ ก็ได้ แต่มันมีประสิทธิภาพน่าทึ่งในการพบบั๊กลึก ๆ ผมเห็นอินเทอร์เฟซแบบมีสถานะจำนวนมากที่แต่ละ operation เองถูกต้อง แต่สมมติฐานของมันเหลื่อมกันนิดหน่อย และเมื่อ operation เหล่านี้ถูกนำมาผสมกันในแบบที่ไม่คาดคิด ก็ลุกลามเป็นความเสียหายภายในได้
      ยังมีประโยชน์มากถ้ารันรายการ operation นี้ควบคู่ไปกับ implementation แบบง่ายที่เป็น in-memory hash table หรือแบบ list แล้วตรวจด้วยว่าผลลัพธ์ตรงกันไหม ถ้าต่างกันก็มักเป็นบั๊ก หรือไม่ก็เป็นกรณีขอบที่ควรมีเอกสารอธิบายให้ดีกว่านี้
    • ผมทำเรื่อง การเพิ่มประสิทธิภาพการขนส่ง เป็นบางครั้ง และมักเจอสถานการณ์ที่ซับซ้อนพอสมควรซึ่ง invariant ถูกทำลาย ถ้ามีตัวย่อ test case คงดีมาก แต่ก่อนหน้านี้ก็ต้องพอใจกับการย่อด้วยมือ[0]
      น่าเสียดายที่ไฟล์ข้อมูลซับซ้อนเกินไปจน shrinkray น่าจะจัดการได้ยาก มันอ่านข้อมูลตารางจาก “ไฟล์” หลายชุดที่แตกต่างกัน และยังมีการพึ่งพากันระยะไกลด้วย ดังนั้นคงต้องเข้ารหัสความรู้เฉพาะโดเมนเกี่ยวกับวิธีย่อเอาเอง
      ด้วยความเร็วของความก้าวหน้าด้าน AI ถ้ามีสถานการณ์แบบนี้อีกครั้งหน้า ผมคงเขียนตัวย่อเฉพาะงานขึ้นมาเอง
      [0] ถ้าจะดึงประเด็นออนโทโลยีที่กำกวมมาใช้ ปัญหาการหาค่าเหมาะที่สุดคือปัญหาการค้นหาที่ทำให้ต้นทุนต่ำสุด และนั่นก็แทบจะเป็นสิ่งเดียวกับคอมไพเลอร์ ดังนั้นจึงไม่ใช่ตัวอย่างที่สมบูรณ์นัก
  • ผมอ่านสามรอบเพื่อพยายามหาว่าจะเอาสิ่งนี้ไปใช้กับเทสต์ที่เขียนด้วย pytest ยังไง
    ผมอยากลดความซับซ้อนของ test suite เลยคิดว่าไว้ว่างจากงานจะกลับมาอ่านรอบที่สี่

    • ถ้าใช้ Python ขั้นแรกคือเอา Hypothesis มาใช้ ซึ่งมีการย่อ test case ติดมาในตัวอยู่แล้ว
  • ปีที่แล้วตอนกำลังดูปัญหาเรื่อง ลำดับการรันเทสต์ ใน CI ผมทำเครื่องมือขึ้นมาตัวหนึ่งเพื่อช่วยย่อรายการเทสต์
    โดยพื้นฐานคือมันลองตัดบรรทัดออกทีละครึ่งแล้วรันดู
    ตัวสคริปต์เองมีบั๊กอยู่พอสมควร แต่การที่รายชื่อเทสต์ 5000 ตัวถูกย่อเหลือประมาณ 4 เทสต์ที่ก่อให้เกิดบั๊กด้าน concurrency ของผมได้นั้นเจ๋งมาก
    ผมสงสัยจริง ๆ ว่าในกรณีของผม Shrink Ray จะใช้ได้เลยหรือเปล่า ผมเชื่อจริง ๆ ว่า “การย่อเซ็ตของบรรทัดโดยอิงจากเทสต์” ควรเป็นความสามารถที่มีอยู่ในชุด เครื่องมือบรรทัดคำสั่ง มาตรฐาน

  • ที่เกี่ยวข้องกับเรื่องนี้ การทดสอบเชิงคุณสมบัติ ก็ใช้แนวทางที่คล้ายกันมาก โดย “ย่อ” state space ของอินพุตที่ถูกสร้างขึ้นมาเพื่อหาตัวอย่างโต้แย้งของการทดสอบ
    ข้อดีของการทดสอบเชิงคุณสมบัติคือคุณสามารถชี้นำและจัดโครงสร้างพื้นที่ค้นหาได้ คุณสามารถทำให้อินพุตเป็นชุดของ transition ที่ขับเคลื่อน state machine ซึ่งใช้จำลองโปรแกรมได้
    ผมยังแปลกใจทุกครั้งที่เห็นว่าเทคนิคนี้ถูกใช้น้อยเกินไป แม้แต่ในโดเมนที่มันเหมาะมากเป็นพิเศษ เช่น ฐานข้อมูลและระบบกระจายศูนย์ แค่สัปดาห์ก่อนเองที่ $WORK ผมสร้างเทสต์ลักษณะนี้ขึ้นมาได้ภายในเวลาไม่กี่ชั่วโมง และก็พบอย่างรวดเร็วว่าระบบของเราไม่ convergent เทสต์พิมพ์ trace ที่สะอาดและเข้าใจได้ทันทีเมื่อเอาไปให้เพื่อนร่วมงานดู
    โดยส่วนตัว ผมมองว่านี่เป็นเทคนิคการทดสอบที่ คุ้มค่าการลงทุน มากที่สุดเวลาต้องดีบักระบบซับซ้อน