ฉันไม่สามารถชี้ไปที่แหล่งข้อมูลออนไลน์ที่ดี (บทความวิกิพีเดียภาษาอังกฤษในหัวข้อเหล่านี้มีแนวโน้มที่จะแก้ไขได้) แต่ฉันสามารถสรุปการบรรยายที่ฉันได้ยินซึ่งครอบคลุมทฤษฎีการทดสอบพื้นฐานด้วย
โหมดการทดสอบ
มีชั้นเรียนที่แตกต่างกันของการทดสอบเป็นเหมือนการทดสอบหน่วยหรือการทดสอบการรวม การทดสอบหน่วยยืนยันว่าชิ้นส่วนที่ต่อเนื่องกันของรหัส (ฟังก์ชั่นคลาสโมดูล) ที่ทำงานด้วยตัวเองตามที่คาดไว้ในขณะที่การทดสอบการรวมเข้าด้วยกันยืนยันว่าชิ้นส่วนดังกล่าวทำงานร่วมกันอย่างถูกต้อง
กรณีทดสอบเป็นสภาพแวดล้อมที่รู้จักกันซึ่งชิ้นส่วนของรหัสจะดำเนินการเช่นโดยใช้การทดสอบการป้อนข้อมูลที่เฉพาะเจาะจงหรือโดยการเยาะเย้ยชั้นเรียนอื่น ๆ พฤติกรรมของรหัสนั้นจะถูกเปรียบเทียบกับพฤติกรรมที่คาดหวังเช่นค่าตอบแทนเฉพาะ
การทดสอบสามารถพิสูจน์การมีอยู่ของบั๊กไม่เคยไม่มีบั๊กทั้งหมด การทดสอบจะเพิ่มขอบเขตความถูกต้องของโปรแกรม
รหัสครอบคลุม
ในการกำหนดตัวชี้วัดความครอบคลุมโค้ดซอร์สโค้ดสามารถแปลเป็นกราฟลำดับการควบคุมที่แต่ละโหนดมีส่วนเชิงเส้นของรหัส ควบคุมโฟลว์ระหว่างโหนดเหล่านี้เฉพาะที่จุดสิ้นสุดของแต่ละบล็อกและอยู่ในเงื่อนไขเสมอ (หากมีเงื่อนไขจากนั้นจะเป็นโหนด A, โหนด goto อื่น, โหนด goto อื่น B) กราฟมีโหนดเริ่มต้นหนึ่งโหนดและโหนดปลายโหนดหนึ่งโหนด
- ด้วยกราฟนี้การครอบคลุมคำสั่งคืออัตราส่วนของโหนดที่เข้าชมทั้งหมดต่อโหนดทั้งหมด การรายงานแบบเต็มไม่เพียงพอสำหรับการทดสอบอย่างละเอียด
- ความครอบคลุมสาขาคืออัตราส่วนของขอบที่เยี่ยมชมทั้งหมดระหว่างโหนดใน CFG ต่อขอบทั้งหมด การทดสอบลูปไม่เพียงพอ
- การครอบคลุมเส้นทางคืออัตราส่วนของเส้นทางที่เข้าชมทั้งหมดต่อเส้นทางทั้งหมดโดยที่เส้นทางคือลำดับของขอบใด ๆ ตั้งแต่เริ่มต้นจนถึงโหนดสุดท้าย ปัญหาคือว่าด้วยลูปอาจมีจำนวนเส้นทางไม่ จำกัด ดังนั้นการครอบคลุมเส้นทางแบบเต็มไม่สามารถทดสอบได้จริง
ดังนั้นจึงเป็นเรื่องที่มักจะมีประโยชน์ในการตรวจสอบเงื่อนไขความคุ้มครอง
- ในการครอบคลุมเงื่อนไขอย่างง่ายแต่ละเงื่อนไขของอะตอมเป็นจริงเพียงครั้งเดียวและเป็นเท็จเพียงครั้งเดียว แต่สิ่งนี้ไม่รับประกันความครอบคลุมคำสั่งทั้งหมด
- ในเงื่อนไขความคุ้มครองหลายเงื่อนไขอะตอมมีการดำเนินการเกี่ยวกับการรวมกันทั้งหมดและ
true
false
สิ่งนี้แสดงให้เห็นถึงความครอบคลุมสาขาเต็มรูปแบบ แต่ค่อนข้างแพง โปรแกรมอาจมีข้อ จำกัด เพิ่มเติมที่ไม่รวมชุดค่าผสมบางอย่าง เทคนิคนี้เป็นสิ่งที่ดีสำหรับการได้รับความคุ้มครองสาขาสามารถค้นหารหัสที่ตายแล้ว แต่ไม่สามารถหาข้อบกพร่องที่เกิดจากสภาพที่ผิด
- ในการครอบคลุมเงื่อนไขน้อยที่สุดหลายเงื่อนไขของอะตอมและคอมโพสิตแต่ละครั้งเป็นจริงและเท็จ มันยังหมายถึงความคุ้มครองเต็มรูปแบบสาขา มันเป็นส่วนย่อยของการครอบคลุมเงื่อนไขหลายอย่าง แต่ต้องใช้กรณีทดสอบน้อยลง
เมื่อสร้างอินพุตทดสอบโดยใช้ความครอบคลุมของเงื่อนไขควรคำนึงถึงการลัดวงจร ตัวอย่างเช่น,
function foo(A, B) {
if (A && B) x()
else y()
}
จะต้องมีการทดสอบกับfoo(false, whatever)
, foo(true, false)
และfoo(true, true)
เต็มน้อยที่สุดเงื่อนไขความคุ้มครองหลาย
หากคุณมีวัตถุที่สามารถอยู่ในหลายสถานะแล้วการทดสอบการเปลี่ยนสถานะทั้งหมดที่คล้ายคลึงกับการควบคุมกระแสดูเหมือนสมเหตุสมผล
มีเมตริกการครอบคลุมที่ซับซ้อนมากขึ้น แต่โดยทั่วไปจะคล้ายกับตัวชี้วัดที่แสดงไว้ที่นี่
นี่คือวิธีการทดสอบกล่องขาวและอาจเป็นแบบอัตโนมัติบางส่วน โปรดทราบว่าชุดทดสอบหน่วยควรมีเป้าหมายเพื่อให้ครอบคลุมรหัสที่สูงโดยเมตริกที่เลือกไว้ แต่ไม่สามารถทำได้ 100% เป็นเรื่องยากโดยเฉพาะอย่างยิ่งในการทดสอบการจัดการข้อยกเว้นซึ่งข้อบกพร่องจะต้องถูกฉีดเข้าไปในสถานที่เฉพาะ
การทดสอบการทำงาน
จากนั้นก็มีการทดสอบการใช้งานซึ่งยืนยันว่ารหัสเป็นไปตามข้อกำหนดโดยดูการใช้งานเป็นกล่องดำ การทดสอบดังกล่าวมีประโยชน์สำหรับการทดสอบหน่วยและการทดสอบการรวมเข้าด้วยกัน เพราะมันเป็นไปไม่ได้ในการทดสอบด้วยการป้อนข้อมูลเป็นไปได้ทั้งหมด (เช่นการทดสอบความยาวสตริงกับสตริงเป็นไปได้ทั้งหมด) ก็จะเป็นประโยชน์ต่อกลุ่มการป้อนข้อมูล (และเอาท์พุท) ในชั้นเรียนเทียบเท่า - ถ้าlength("foo")
ถูกต้องfoo("bar")
มีแนวโน้มที่จะทำงานได้เป็นอย่างดี สำหรับการรวมกันที่เป็นไปได้ระหว่างคลาสและอินเทอร์เฟซที่เทียบเท่าเอาต์พุตคลาสตัวแทนที่เลือกอย่างน้อยหนึ่งรายการจะถูกเลือกและทดสอบ
หนึ่งควรทดสอบเพิ่มเติม
- กรณีขอบ
length("")
, foo("x")
, length(longer_than_INT_MAX)
,
- ค่าที่ได้รับอนุญาตโดยภาษา แต่ไม่ได้ตามสัญญาของฟังก์ชั่น
length(null)
และ
- ข้อมูลขยะที่เป็นไปได้
length("null byte in \x00 the middle")
...
ด้วยตัวเลขนี่หมายถึงการทดสอบ0, ±1, ±x, MAX, MIN, ±∞, NaN
และด้วยการเปรียบเทียบจุดลอยตัวทดสอบการลอยตัวสองตัวใกล้เคียง นอกจากนี้ยังสามารถเลือกค่าการทดสอบแบบสุ่มจากคลาสการเทียบเท่า เพื่อความสะดวกในการดีบั๊กมันคุ้มค่าที่จะบันทึกเมล็ดพันธุ์ที่ใช้ ...
การทดสอบที่ใช้งานไม่ได้: การทดสอบโหลดการทดสอบความเครียด
ซอฟต์แวร์บางส่วนมีข้อกำหนดที่ไม่สามารถใช้งานได้ซึ่งจะต้องมีการทดสอบเช่นกัน สิ่งเหล่านี้รวมถึงการทดสอบตามขอบเขตที่กำหนด (การทดสอบโหลด) และนอกเหนือจากนั้น (การทดสอบความเครียด) สำหรับเกมคอมพิวเตอร์นี่อาจเป็นการ จำกัด จำนวนเฟรมต่อวินาทีขั้นต่ำในการทดสอบโหลด เว็บไซต์อาจได้รับการทดสอบอย่างเข้มงวดเพื่อสังเกตเวลาตอบสนองเมื่อมีผู้เข้าชมมากเป็นสองเท่าตามที่คาดการณ์ไว้ การทดสอบดังกล่าวไม่เพียง แต่เกี่ยวข้องกับทั้งระบบเท่านั้น แต่ยังรวมถึงหน่วยงานเดียวด้วยเช่นกัน - ตารางแฮชจะลดขนาดลงได้อย่างไร
การทดสอบประเภทอื่น ๆ เป็นการทดสอบทั้งระบบที่จำลองสถานการณ์หรือการทดสอบการยอมรับเพื่อพิสูจน์ว่าสัญญาการพัฒนานั้นสำเร็จ
วิธีการที่ไม่ใช่การทดสอบ
ความคิดเห็น
มีเทคนิคที่ไม่ใช่การทดสอบที่สามารถใช้สำหรับการประกันคุณภาพ ตัวอย่างคือคำแนะนำการใช้งานการตรวจสอบโค้ดอย่างเป็นทางการหรือการเขียนโปรแกรมคู่ ในขณะที่บางส่วนสามารถเป็นแบบอัตโนมัติ (เช่นโดยใช้ linters) โดยทั่วไปจะใช้เวลานาน อย่างไรก็ตามการตรวจสอบโค้ดโดยโปรแกรมเมอร์ที่มีประสบการณ์มีอัตราการค้นพบบั๊กสูงและมีค่ามากในระหว่างการออกแบบซึ่งไม่สามารถทำการทดสอบอัตโนมัติได้
เมื่อความคิดเห็นเกี่ยวกับโค้ดดีมากทำไมเราถึงยังเขียนการทดสอบอยู่ ประโยชน์ใหญ่ของห้องทดสอบก็คือพวกเขาสามารถทำงานได้ (ส่วนใหญ่) โดยอัตโนมัติและจะเป็นเช่นนี้มีประโยชน์มากสำหรับการทดสอบการถดถอย
การตรวจสอบอย่างเป็นทางการ
การตรวจสอบอย่างเป็นทางการดำเนินไปและพิสูจน์คุณสมบัติบางประการของรหัส การตรวจสอบด้วยตนเองส่วนใหญ่จะทำงานได้สำหรับชิ้นส่วนที่สำคัญน้อยกว่าสำหรับโปรแกรมทั้งหมด พิสูจน์ทำให้ขอบเขตที่ต่ำกว่าในความถูกต้องของโปรแกรม พิสูจน์ได้โดยอัตโนมัติในระดับหนึ่งเช่นผ่านตัวตรวจสอบชนิดคงที่
ค่าคงที่บางอย่างสามารถตรวจสอบได้อย่างชัดเจนโดยใช้assert
คำสั่ง
เทคนิคเหล่านี้ทั้งหมดมีสถานที่และประกอบ TDD เขียนการทดสอบการใช้งานไว้ล่วงหน้า แต่การทดสอบนั้นสามารถตัดสินได้จากการวัดความครอบคลุมเมื่อมีการใช้รหัส
การเขียนรหัสที่สามารถทดสอบได้หมายถึงการเขียนหน่วยรหัสขนาดเล็กที่สามารถทดสอบแยกต่างหาก (ฟังก์ชั่นผู้ช่วยที่มีความละเอียดที่เหมาะสมหลักการความรับผิดชอบเดี่ยว) อาร์กิวเมนต์ที่น้อยลงในแต่ละฟังก์ชั่นก็จะดีขึ้น รหัสดังกล่าวยังให้ยืมตัวเองเพื่อแทรกวัตถุจำลองเช่นผ่านการฉีดพึ่งพา
double pihole(double value) { return (value - Math.PI) / (value - Math.PI); }
ซึ่งฉันได้เรียนรู้จากครูคณิตศาสตร์ของฉัน รหัสนี้มีรูเดียวซึ่งไม่สามารถค้นพบได้โดยอัตโนมัติจากการทดสอบกล่องดำเพียงอย่างเดียว ในวิชาคณิตศาสตร์ไม่มีหลุมดังกล่าว ในแคลคูลัสคุณจะได้รับอนุญาตให้ปิดหลุมหากขีด จำกัด ด้านเดียวเท่ากัน