เขียนหน่วยทดสอบด้วยตนเองพิสูจน์ตามตัวอย่างหรือไม่


9

เรารู้ว่าการเขียนการทดสอบJUnitแสดงให้เห็นถึงเส้นทางหนึ่งผ่านรหัสของคุณ

หนึ่งในผู้ร่วมงานของฉันแสดงความคิดเห็น:

เขียนด้วยตนเองทดสอบหน่วยเป็นหลักฐานตามตัวอย่าง

เขาเป็นคนที่มาจากพื้นหลังของ Haskell ซึ่งมีเครื่องมือเช่นQuickCheckและความสามารถในเหตุผลเกี่ยวกับการทำงานของโปรแกรมประเภท

ความหมายของเขาคือมีชุดค่าผสมอื่น ๆ มากมายซึ่งไม่ได้ทดสอบโดยวิธีนี้ซึ่งไม่ได้ทดสอบรหัสของคุณ

คำถามของฉันคือ: เขียนหน่วยทดสอบด้วยตนเองพิสูจน์ตามตัวอย่าง?


3
ไม่ไม่เขียน / ใช้แบบทดสอบ การอ้างว่าการทดสอบหน่วยของคุณเป็นเครื่องพิสูจน์ว่าไม่มีอะไรผิดปกติกับโปรแกรมคือการพิสูจน์ตามตัวอย่าง (การวางนัยทั่วไปที่ไม่เหมาะสม) การทดสอบไม่ได้เกี่ยวกับการพิสูจน์ความถูกต้องทางคณิตศาสตร์ แต่การทดสอบนั้นเป็นการทดสอบทางธรรมชาติ เป็นตาข่ายนิรภัยที่ช่วยให้คุณสร้างความมั่นใจด้วยการบอกบางสิ่งเกี่ยวกับรหัส แต่คุณเป็นคนที่ต้องเลือกกลยุทธ์ที่ดีในการตรวจสอบรหัสและคุณเป็นคนที่ต้องตีความความหมายของข้อมูลนั้น
Filip Milovanović

คำตอบ:


10

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

แต่การทดสอบหน่วยที่ดีไม่เคยทำอย่างนั้น แต่จะจัดการในช่วงและกรณีขอบ

ตัวอย่างเช่นหากคุณต้องเขียนการทดสอบหน่วยสำหรับฟังก์ชั่นค่าสัมบูรณ์ที่รับจำนวนเต็มเป็นอินพุตคุณไม่จำเป็นต้องทดสอบค่าที่เป็นไปได้ทุกค่าเพื่อพิสูจน์ว่ารหัสทำงาน ในการรับการทดสอบที่ครอบคลุมคุณจะต้องมีเพียงห้าค่าเท่านั้น: -1, 0, 1 และค่าสูงสุดและต่ำสุดสำหรับจำนวนเต็มเข้า

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


11
เครื่องทดสอบรหัสเข้าสู่บาร์และสั่งเบียร์ 5 เบียร์ -1 เบียร์, MAX_VALUE เบียร์, ไก่ เป็นโมฆะ
Neil

2
"5 ค่า" เป็นเรื่องไร้สาระ พิจารณาการทำงานเล็ก ๆ น้อย ๆ int foo(int x) { return 1234/(x - 100); }เช่น โปรดทราบว่า (ขึ้นอยู่กับสิ่งที่คุณกำลังทดสอบ) คุณอาจต้องตรวจสอบให้แน่ใจว่าอินพุต ("นอกขอบเขต") ไม่ถูกต้องส่งคืนผลลัพธ์ที่ถูกต้อง (เช่นว่า `` find_thing (สิ่ง)) ส่งกลับสถานะ "ไม่พบ" บางประเภทอย่างถูกต้อง หากไม่พบสิ่งนั้น)
เบรนแดน

3
@Brendan: ไม่มีอะไรสำคัญเกี่ยวกับมันเป็นห้าค่า; มันแค่เป็นค่าห้าค่าในตัวอย่างของฉัน ตัวอย่างของคุณมีจำนวนการทดสอบที่แตกต่างกันเพราะคุณกำลังทดสอบฟังก์ชั่นที่แตกต่างกัน ฉันไม่ได้บอกว่าทุกฟังก์ชั่นต้องการการทดสอบห้าประการ คุณอนุมานได้ว่าจากการอ่านคำตอบของฉัน
Robert Harvey

1
ไลบรารีการทดสอบทั่วไปมักจะดีกว่าในการทดสอบกรณีขอบกว่าคุณ ตัวอย่างเช่นถ้าคุณกำลังใช้ลอยแทนจำนวนเต็มห้องสมุดของคุณยังจะตรวจสอบ-Inf, Inf, NaN, 1e-100, -1e-100, -0, 2e200... ฉันต้องการ แต่ไม่ต้องทำเหล่านั้นด้วยตนเอง
Hovercouch

@Hovercouch: ถ้าคุณรู้จักของดีฉันชอบที่จะได้ยินเกี่ยวกับมัน สิ่งที่ดีที่สุดที่ฉันเคยเห็นคือ Pex; แม้ว่ามันจะไม่เสถียรอย่างไม่น่าเชื่อ จำไว้ว่าเรากำลังพูดถึงฟังก์ชั่นที่ค่อนข้างง่ายที่นี่ สิ่งต่างๆจะยากขึ้นเมื่อคุณจัดการกับสิ่งต่าง ๆ เช่นตรรกะทางธุรกิจในชีวิตจริง
Robert Harvey

8

การทดสอบซอฟต์แวร์ใด ๆก็เหมือน "หลักฐานตามตัวอย่าง" ไม่เพียง แต่การทดสอบหน่วยโดยใช้เครื่องมือเช่น JUnit และนั่นไม่ใช่ภูมิปัญญาใหม่มีคำพูดจากDijkstraจากปี 1960 ซึ่งบอกว่าเป็นหลักเดียวกัน:

"การทดสอบแสดงให้เห็นว่าไม่มีแมลงอยู่"

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

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

ดังนั้นการทดสอบที่สร้างขึ้นด้วยตนเองจะไม่เลวร้ายไปกว่าการทดสอบที่สร้างแบบสุ่มซึ่งมักจะตรงกันข้าม


1
ชุดทดสอบจริงใด ๆ ที่ใช้การตรวจสอบแบบสุ่มจะมีการทดสอบหน่วยด้วย (ในทางเทคนิคแล้วการทดสอบหน่วยเป็นเพียงแค่การทดสอบแบบสุ่มที่เสื่อมลง) ถ้อยคำของคุณแสดงให้เห็นว่าการทดสอบแบบสุ่มนั้นยากที่จะบรรลุผลหรือการรวมการทดสอบแบบสุ่มและการทดสอบหน่วยเป็นเรื่องยาก นี่ไม่ใช่กรณีทั่วไป ในความคิดของฉันหนึ่งในประโยชน์ที่ใหญ่ที่สุดของการทดสอบแบบสุ่มคือมันสนับสนุนให้มีการทดสอบการเขียนเป็นคุณสมบัติเกี่ยวกับรหัสที่มีไว้เพื่อเสมอ ฉันค่อนข้างจะมีคุณสมบัติเหล่านี้ระบุไว้อย่างชัดเจน (และตรวจสอบ!) กว่าจะต้องสรุปพวกเขาทดสอบจุด
Derek Elkins ออกจาก SE

@DerekElkins: "ยาก" IMHO เป็นคำที่ผิด การทดสอบแบบสุ่มต้องใช้ความพยายามค่อนข้างมากและนั่นคือความพยายามที่ช่วยลดเวลาที่มีสำหรับการทำแบบทดสอบด้วยมือ (และถ้าคุณมีคนติดตามคำขวัญเหมือนกับที่กล่าวถึงในคำถาม เพียงแค่โยนข้อมูลการทดสอบแบบสุ่มจำนวนมากลงบนชิ้นส่วนของรหัสก็เป็นเพียงครึ่งหนึ่งของการทำงานหนึ่งยังมีการสร้างผลลัพธ์ที่คาดหวังสำหรับแต่ละอินพุตการทดสอบ สำหรับบางสถานการณ์สิ่งนี้สามารถทำได้โดยอัตโนมัติ สำหรับคนอื่นไม่
Doc Brown

ในขณะที่มีบางครั้งที่จำเป็นต้องใช้ความคิดบางอย่างเพื่อเลือกการแจกแจงที่ดีซึ่งโดยปกติจะไม่เป็นการแฮงค์ที่สำคัญ ความคิดเห็นของคุณแสดงให้เห็นว่าคุณกำลังคิดเกี่ยวกับวิธีที่ผิด คุณสมบัติที่คุณเขียนสำหรับการตรวจสอบแบบสุ่มเป็นคุณสมบัติเดียวกันกับที่คุณจะเขียนเพื่อตรวจสอบแบบจำลองหรือเพื่อพิสูจน์อย่างเป็นทางการ แน่นอนพวกเขาสามารถและถูกนำมาใช้สำหรับทุกสิ่งในเวลาเดียวกัน ไม่มี "ผลลัพธ์ที่คาดหวัง" ที่คุณต้องการเช่นกัน คุณเพียงแค่ระบุคุณสมบัติที่ควรถือไว้เสมอ ตัวอย่าง: 1) ผลักบางสิ่งบางอย่างลงบนสแต็กและ ...
Derek Elkins ออกจาก SE

... จากนั้น popping ควรจะเหมือนกับการไม่ทำอะไรเลย 2) ลูกค้าที่มียอดคงเหลือมากกว่า $ 10,000 ควรได้รับอัตราดอกเบี้ยที่สูงและหลังจากนั้น 3) ตำแหน่งสไปรต์อยู่เสมอภายในกรอบของหน้าจอ คุณสมบัติบางอย่างอาจสอดคล้องกับการทดสอบจุดเช่น "เมื่อยอดคงเหลือเท่ากับ $ 0 ให้คำเตือนยอดคงเหลือเป็นศูนย์" คุณสมบัติเป็นคุณสมบัติบางส่วนที่มีคุณสมบัติในการรับข้อมูลจำเพาะทั้งหมด การมีปัญหาในการคิดคุณสมบัติเหล่านี้หมายความว่าคุณไม่ชัดเจนว่าข้อมูลจำเพาะคืออะไรและบ่อยครั้งหมายความว่าคุณมีปัญหาในการคิดการทดสอบหน่วยที่ดี
Derek Elkins ออกจาก SE

0

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

การทดสอบทั่วไปเช่น QuickCheck นั้นดีมากสำหรับการกวาดอินพุตจำนวนมาก นอกจากนี้ยังดีกว่ามากสำหรับการแก้ปัญหากรณีขอบกว่าการทดสอบด้วยตนเอง: ห้องสมุดทดสอบทั่วไปจะมีประสบการณ์มากกว่านี้กับคุณ ในทางกลับกันพวกเขาเพียง แต่บอกคุณเกี่ยวกับค่าคงที่ไม่ใช่ผลลัพธ์เฉพาะ ดังนั้นเพื่อตรวจสอบว่าโปรแกรมของคุณได้รับผลลัพธ์ที่ถูกต้องคุณยังต้องมีการทดสอบด้วยตนเองเพื่อยืนยันว่าในความเป็นจริงfoo(bar) = bazแล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.