คุณจะเขียนการทดสอบหน่วยสำหรับโค้ดที่คาดเดาผลลัพธ์ได้ยากอย่างไร


124

ฉันทำงานกับโปรแกรมตัวเลข / คณิตศาสตร์บ่อยครั้งมากซึ่งผลลัพธ์ที่แน่นอนของฟังก์ชั่นนั้นยากที่จะทำนายล่วงหน้า

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

มีเทคนิคที่รู้จักกันสำหรับการเขียนการทดสอบหน่วยและการใช้ TDD เมื่อผลลัพธ์ของรหัสภายใต้การทดสอบนั้นยากที่จะทำนายหรือไม่?

ตัวอย่างโค้ด (จริง) ที่ยากต่อการคาดการณ์ผลลัพธ์:

ฟังก์ชั่นweightedTasksOnTimeที่ได้รับจำนวนเงินของงานที่ทำต่อวันworkPerDayในช่วง (0, 24], เวลาปัจจุบันinitialTime> 0 และรายชื่อของงานtaskArrayแต่ละที่มีเวลาที่จะเสร็จสมบูรณ์คุณสมบัติtime> 0 วันที่ครบกำหนดdueและความคุ้มค่าความสำคัญimportance; ผลตอบแทน ค่าปกติอยู่ในช่วง [0, 1] เป็นตัวแทนของความสำคัญของงานที่สามารถจะแล้วเสร็จก่อนของพวกเขาdueวันถ้าแต่ละงานถ้าเสร็จสมบูรณ์ในการสั่งซื้อที่กำหนดโดยเริ่มต้นที่taskArrayinitialTime

ขั้นตอนวิธีการที่จะใช้ฟังก์ชั่นนี้ค่อนข้างตรงไปตรงมา: taskArrayย้ำกว่างานใน สำหรับแต่ละงานเพิ่มเพื่อtime initialTimeหากเวลาใหม่ < dueเพิ่มimportanceไปยังแอคคูมูเลเตอร์ ปรับเวลาด้วย inverse workPerDay ก่อนที่จะส่งคืนตัวสะสมหารด้วยผลรวมของความสำคัญของงานเพื่อทำให้ปกติ

function weightedTasksOnTime(workPerDay, initialTime, taskArray) {
    let simulatedTime = initialTime
    let accumulator = 0;
    for (task in taskArray) {
        simulatedTime += task.time * (24 / workPerDay)
        if (simulatedTime < task.due) {
            accumulator += task.importance
        }
    }
    return accumulator / totalImportance(taskArray)
}

ฉันเชื่อว่าปัญหาข้างต้นสามารถทำให้เข้าใจง่ายขึ้นในขณะที่ยังคงรักษาแกนหลักไว้โดยการลบworkPerDayและข้อกำหนดมาตรฐานเพื่อให้:

function weightedTasksOnTime(initialTime, taskArray) {
    let simulatedTime = initialTime
    let accumulator = 0;
    for (task in taskArray) {
        simulatedTime += task.time
        if (simulatedTime < task.due) {
            accumulator += task.importance
        }
    }
    return accumulator
}

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


4
คุณสามารถให้ตัวอย่างง่ายๆของฟังก์ชันที่ผลลัพธ์ยากต่อการคาดเดาหรือไม่?
Robert Harvey

62
FWIW คุณไม่ได้ทดสอบอัลกอริทึม สันนิษฐานว่าถูกต้อง คุณกำลังทดสอบการใช้งาน การออกกำลังกายด้วยมือมักเป็นเรื่องปกติเนื่องจากการก่อสร้างแบบขนาน
Kristian H


7
มีบางสถานการณ์ที่อัลกอริทึมไม่สามารถทดสอบหน่วยได้อย่างสมเหตุสมผล - ตัวอย่างเช่นหากเวลาดำเนินการเป็นหลายวัน / เดือน สิ่งนี้อาจเกิดขึ้นเมื่อแก้ปัญหา NP ในกรณีเหล่านี้อาจเป็นไปได้มากกว่าที่จะให้การพิสูจน์อย่างเป็นทางการว่ารหัสถูกต้อง
Hulk

12
สิ่งที่ฉันเห็นในรหัสตัวเลขที่ยุ่งยากมากคือการทดสอบหน่วยทดสอบเป็นการทดสอบการถดถอยเท่านั้น เขียนฟังก์ชันเรียกใช้สำหรับค่าที่น่าสนใจหลายอย่างตรวจสอบผลลัพธ์ด้วยตนเองจากนั้นเขียนการทดสอบหน่วยเพื่อตรวจสอบการถดถอยจากผลลัพธ์ที่คาดไว้ การเข้ารหัสสยองขวัญ? อยากรู้ว่าคนอื่นคิดอย่างไร
Chuu

คำตอบ:


251

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

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

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


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

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

7
การตรวจสอบสติมักจะทำให้เป้าหมายที่ดีสำหรับการทดสอบตามคุณสมบัติกับ QuickCheck
jk

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

5
@iFlo ไม่แน่ใจว่าคุณล้อเล่นหรือยัง น่ารู้ว่าการทดสอบที่ล้มเหลวอาจเป็นปัญหาในฟังก์ชั่นผกผัน
lucidbrot

80

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

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


32
Metamorphic Relations เป็นตัวอย่างที่เฉพาะเจาะจงของการทดสอบตามคุณสมบัติซึ่งโดยทั่วไปแล้วเป็นเครื่องมือที่มีประโยชน์สำหรับสถานการณ์เช่นนี้
Dannnno

38

คำตอบอื่น ๆ มีแนวคิดที่ดีสำหรับการพัฒนาแบบทดสอบสำหรับกรณีขอบหรือข้อผิดพลาด สำหรับคนอื่น ๆ การใช้อัลกอริทึมนั้นไม่เหมาะ (ชัด) แต่ก็ยังมีประโยชน์

มันจะตรวจสอบว่าอัลกอริทึม (หรือข้อมูลมันขึ้นอยู่กับ) มีการเปลี่ยนแปลง

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


6
และสำหรับบันทึกการทดสอบประเภทนี้มักจะเรียกว่า "การทดสอบการถดถอย" ตามวัตถุประสงค์ของพวกเขาและโดยทั่วไปจะเป็นตาข่ายความปลอดภัยสำหรับการดัดแปลง / การปรับสภาพใหม่
Pac0

21

เช่นเดียวกับที่คุณเขียนการทดสอบหน่วยสำหรับโค้ดประเภทอื่น:

  1. ค้นหากรณีทดสอบตัวแทนและทดสอบกรณีเหล่านี้
  2. ค้นหาเคสและทดสอบเคสเหล่านั้น
  3. ค้นหาเงื่อนไขข้อผิดพลาดและทดสอบเงื่อนไขเหล่านั้น

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

หลีกเลี่ยงผลข้างเคียงหรือฟังก์ชั่นที่ได้รับผลกระทบจากแรงภายนอก ฟังก์ชั่นที่บริสุทธิ์นั้นง่ายต่อการทดสอบ


2
สำหรับอัลกอริทึมที่ไม่สามารถกำหนดค่าได้คุณสามารถบันทึกเมล็ดพันธุ์ของ RNG หรือจำลองโดยใช้ชุดลำดับคงที่หรือชุดค่าคงที่ความคลาดเคลื่อนต่ำเช่นลำดับ Halton
wondra

14
@ PaintingInAir หากไม่สามารถตรวจสอบผลลัพธ์ของอัลกอริทึมได้อัลกอริทึมอาจผิดพลาดได้หรือไม่?
WolfgangGroiss

5
Unless your code involves some random elementเคล็ดลับที่นี่คือการทำให้ตัวสร้างตัวเลขสุ่มของคุณเป็นแบบพึ่งพาการฉีดดังนั้นคุณสามารถแทนที่มันเป็นตัวสร้างตัวเลขซึ่งให้ผลลัพธ์ที่แน่นอนที่คุณต้องการ สิ่งนี้ช่วยให้คุณสามารถทดสอบได้อย่างแม่นยำอีกครั้ง - นับจำนวนที่สร้างขึ้นเป็นพารามิเตอร์อินพุตเช่นกัน not deterministic (i.e. it won't produce the same output given the same input)เนื่องจากการทดสอบหน่วยควรเริ่มจากสถานการณ์ที่มีการควบคุมจึงอาจไม่สามารถกำหนดได้ถ้ามันมีองค์ประกอบแบบสุ่มซึ่งคุณสามารถฉีดได้ ฉันไม่สามารถคิดความเป็นไปได้อื่น ๆ ได้ที่นี่
Flater

3
@PaintInAir: อย่างใดอย่างหนึ่งหรือ ความคิดเห็นของฉันใช้กับทั้งการดำเนินการที่รวดเร็วหรือการเขียนทดสอบที่รวดเร็ว หากคุณใช้เวลาสามวันในการคำนวณตัวอย่างด้วยมือ (สมมติว่าคุณใช้วิธีที่เร็วที่สุดที่ไม่ได้ใช้รหัส) - จากนั้นสามวันคือสิ่งที่จะต้องใช้ หากคุณใช้ผลการทดสอบตามที่คาดหวังจากรหัสจริงของตัวเองการทดสอบจะลดลง มันเหมือนกับการทำif(x == x)มันเป็นการเปรียบเทียบที่ไร้จุดหมาย คุณต้องการผลลัพธ์ทั้งสองของคุณ ( จริง : มาจากโค้ดคาดหวัง : มาจากความรู้ภายนอกของคุณ) เพื่อให้เป็นอิสระจากกัน
Flater

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

17

อัปเดตเนื่องจากความคิดเห็นที่โพสต์

คำตอบเดิมถูกลบออกเพราะเห็นได้ชัดว่าสั้น - คุณสามารถค้นหาได้ในประวัติการแก้ไข

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

ก่อนอื่นTL; DRเพื่อหลีกเลี่ยงคำตอบที่ยาวเกินไป:

ลองวิธีนี้ดู:
ลูกค้าเข้ามาใน McDonald's แล้วถามหาเบอร์เกอร์ที่มีผักกาดหอมมะเขือเทศและสบู่มือเป็นท็อปปิ้ง คำสั่งนี้จะมอบให้กับผู้ปรุงอาหารซึ่งทำเบอร์เกอร์ตามที่ร้องขอ ลูกค้าได้รับเบอร์เกอร์นี้กินแล้วบ่นกับพ่อครัวว่านี่ไม่ใช่เบอร์เกอร์แสนอร่อย!

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

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

แม้ว่าคุณจะเป็นทั้งลูกค้าและผู้ปรุงอาหาร แต่ก็ยังมีความแตกต่างที่มีความหมายระหว่าง:

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

ปัญหาหลักของที่นี่คือคุณไม่ได้ทำการแยกระหว่างลูกค้าและนักพัฒนา (และนักวิเคราะห์ - แม้ว่าผู้พัฒนาจะสามารถแสดงบทบาทนั้นได้)

คุณต้องแยกความแตกต่างระหว่างการทดสอบรหัสและการทดสอบข้อกำหนดทางธุรกิจ

ตัวอย่างเช่นลูกค้าต้องการไปทำงานเช่น[นี้] อย่างไรก็ตามนักพัฒนา misunderstands และเขาเขียนรหัสที่ไม่[ว่า]

ผู้พัฒนาจึงจะเขียนการทดสอบหน่วยที่ทดสอบว่า[นั้น]ทำงานได้ตามที่คาดไว้หรือไม่ หากเขาพัฒนาแอปพลิเคชันอย่างถูกต้องการทดสอบหน่วยของเขาจะผ่านแม้ว่าแอปพลิเคชันจะไม่ทำ[สิ่งนี้]ซึ่งลูกค้าคาดหวัง

หากคุณต้องการทดสอบความคาดหวังของลูกค้า (ข้อกำหนดทางธุรกิจ) นั่นจะต้องทำในขั้นตอนแยกต่างหาก (และใหม่กว่า)

เวิร์กโฟลว์การพัฒนาอย่างง่ายที่จะแสดงให้คุณเห็นเมื่อควรทำการทดสอบเหล่านี้:

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

คุณอาจสงสัยว่าจุดประสงค์ของการทดสอบสองแบบแยกกันคืออะไรเมื่อลูกค้าและนักพัฒนาเป็นแบบเดียวกัน เนื่องจากไม่มี "การส่งมอบ" จากผู้พัฒนาไปยังลูกค้าการทดสอบจึงดำเนินการอย่างต่อเนื่อง แต่ยังคงมีขั้นตอนแยกกัน

  • การทดสอบหน่วยเป็นเครื่องมือพิเศษที่ช่วยให้คุณตรวจสอบว่าขั้นตอนการพัฒนาของคุณเสร็จสิ้นหรือไม่
  • การทดสอบ QA จะทำโดยใช้โปรแกรม

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

ในฐานะผู้ประกอบการและนักวิชาการคุณอาจพลาดความแตกต่างที่สำคัญที่นี่ซึ่งเน้นความรับผิดชอบที่แตกต่างกัน

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

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

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

2
@PaintInAir: มันอันตรายที่จะจับคู่ลูกค้านักวิเคราะห์และนักพัฒนาให้แน่น ในขณะที่คุณกำลังมีแนวโน้มที่จะข้ามขั้นตอนที่สำคัญเช่นการกำหนดจุดเริ่มต้นของปัญหา ฉันเชื่อว่านั่นคือสิ่งที่คุณทำที่นี่ ดูเหมือนว่าคุณต้องการทดสอบความถูกต้องของอัลกอริทึมแทนที่จะใช้ว่าถูกต้องหรือไม่ แต่นั่นไม่ใช่วิธีที่คุณทำ การทดสอบการใช้งานสามารถทำได้โดยใช้การทดสอบหน่วย การทดสอบอัลกอริทึมนั้นเป็นเรื่องของการใช้แอปพลิเคชัน (ทดสอบ) ของคุณและการตรวจสอบข้อเท็จจริง - การทดสอบจริงนี้อยู่นอกขอบเขตของโค้ดเบสของคุณ (เท่าที่ควร )
Flater

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

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

9

การทดสอบอสังหาริมทรัพย์

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

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

หนึ่งในการแนะนำที่ดีที่สุดในการทดสอบอสังหาริมทรัพย์ที่ฉันเคยเห็นคือหนึ่งใน F # หวังว่าไวยากรณ์ไม่ใช่สิ่งกีดขวางที่จะเข้าใจคำอธิบายของเทคนิค


1
ฉันขอแนะนำให้เพิ่มบางอย่างที่เฉพาะเจาะจงในตัวอย่างของคุณเช่นการสร้าง quartets แบบสุ่ม (a, b, c) และยืนยันว่า (ab) (cd) ให้ผลผลิต (ac-ad) - (bc-bd) การดำเนินการที่ทวีคูณอาจจะแตกหักสวยและยังคงรักษากฎ (ลบครั้งลบให้ผลบวก) แต่กฎการกระจายคาดการณ์ผลลัพธ์ที่เฉพาะเจาะจง
supercat

4

มันเป็นการล่อลวงให้เขียนโค้ดแล้วดูว่าผลการค้นหา "ถูกต้อง" หรือไม่ แต่เป็นความคิดที่ถูกต้อง

เมื่ออัลกอริทึมยากคุณสามารถทำสิ่งต่าง ๆ เพื่อให้การคำนวณผลลัพธ์ด้วยตนเองง่ายขึ้น

  1. ใช้ Excel ตั้งค่าสเปรดชีตที่ใช้ในการคำนวณบางส่วนหรือทั้งหมดสำหรับคุณ ทำให้เรียบง่ายพอเพื่อให้คุณสามารถดูขั้นตอน

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

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

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


สำหรับ 3. ให้อนุญาตข้อผิดพลาดในการปัดเศษที่นี่ เป็นไปได้ว่าจำนวนรวมของคุณเป็น 100,000001% หรือตัวเลขใกล้เคียง แต่ไม่ใกล้เคียงกัน
Flater

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

6
@ flater มักจะมีข้อกำหนดอื่น ๆ รวมถึงความถูกต้องที่เดรัจฉานไม่ตอบสนอง เช่นประสิทธิภาพ
Ewan

1
@ flater ฉันไม่ชอบที่จะใช้การเรียงลำดับเส้นทางที่สั้นที่สุดเครื่องมือหมากรุก ฯลฯ หากคุณเชื่ออย่างนั้น แต่ id เล่นการพนันโดยสิ้นเชิงในข้อผิดพลาดในการปัดเศษของคุณอนุญาตให้คาสิโนตลอดทั้งวัน
Ewan

3
@ flater คุณลาออกเมื่อคุณได้เล่นเกมจบเกม king king หรือไม่? เพียงเพราะเกมทั้งหมดไม่สามารถบังคับสัตว์เดรัจฉานไม่ได้หมายความว่าไม่สามารถทำตำแหน่งได้ เพียงเพราะคุณเดรัจฉานบังคับให้เส้นทางที่สั้นที่สุดที่ถูกต้องไปยังเครือข่ายเดียวไม่ได้หมายความว่าคุณจะรู้เส้นทางที่สั้นที่สุดในทุกเครือข่าย
Ewan

2

TL; DR

ไปที่ส่วน "การทดสอบเปรียบเทียบ" สำหรับคำแนะนำที่ไม่ได้อยู่ในคำตอบอื่น ๆ


เป็นจุดเริ่มต้น

เริ่มต้นด้วยการทดสอบเคสที่ควรถูกปฏิเสธโดยอัลกอริทึม ( workPerDayตัวอย่างเช่นศูนย์หรือลบ) และกรณีที่ไม่สำคัญ (เช่นtasksอาร์เรย์ว่าง)

หลังจากนั้นคุณต้องการทดสอบกรณีที่ง่ายที่สุดก่อน สำหรับtasksอินพุตเราต้องทดสอบความยาวที่แตกต่างกัน มันควรจะเพียงพอที่จะทดสอบองค์ประกอบ 0, 1 และ 2 (2 เป็นของหมวดหมู่ "มาก" สำหรับการทดสอบนี้)

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

การทดสอบเปรียบเทียบ

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

fallbacks

บางครั้งฉันต้องหันไปใช้ความคิดเห็นที่ยาวแสดงผลลัพธ์ที่คำนวณด้วยมือในขั้นตอนที่สอดคล้องกับข้อมูลจำเพาะ (ความคิดเห็นดังกล่าวมักจะยาวกว่ากรณีทดสอบ) กรณีที่เลวร้ายที่สุดคือเมื่อคุณต้องรักษาความเข้ากันได้กับการใช้งานก่อนหน้านี้ในภาษาอื่นหรือสำหรับสภาพแวดล้อมที่แตกต่างกัน /* derived from v2.6 implementation on ARM system */บางครั้งคุณก็ต้องติดป้ายข้อมูลการทดสอบกับสิ่งที่ต้องการ นั่นไม่ได้เป็นที่น่าพอใจมากนัก แต่อาจยอมรับได้ว่าเป็นแบบทดสอบความซื่อสัตย์เมื่อทำการพอร์ตหรือเป็นไม้ยันรักแร้ระยะสั้น

การแจ้งเตือน

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

อย่าลืมใช้ "ประมาณเท่ากับ" ที่เหมาะสมสำหรับผลลัพธ์ที่ไม่แน่นอน (เช่นจุดลอยตัว)

หลีกเลี่ยงการทดสอบมากเกินไป - เพิ่มการทดสอบหากครอบคลุมบางสิ่ง (เช่นค่าขอบเขต) ที่การทดสอบอื่นไม่ถึง


2

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

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

จากนั้นเห็นได้ชัดว่านำกรณีขอบเช่น (ในตัวอย่างของคุณ) รายการงานว่าง สิ่งเช่นนั้น

ชุดทดสอบของคุณอาจไม่ดีเท่าวิธีการที่คุณสามารถคาดการณ์ผลลัพธ์ได้อย่างง่ายดาย แต่ก็ยังดีกว่าไม่มีชุดทดสอบ 100% (หรือทดสอบควัน)

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

หากเป็นกรณีปกติสำหรับคุณคุณต้องพูดคุยอย่างหนักกับวิศวกรที่มีความต้องการของคุณ หากพวกเขาไม่สามารถกำหนดความต้องการของคุณในวิธีที่ง่าย (หรือที่เป็นไปได้ทั้งหมด) เพื่อตรวจสอบให้คุณจากนั้นเมื่อคุณรู้ว่าคุณจะเสร็จสิ้น?


2

คำตอบอื่น ๆ เป็นสิ่งที่ดีดังนั้นฉันจะพยายามตีในบางจุดที่พวกเขาพลาดโดยรวม

ฉันได้เขียนซอฟต์แวร์ (และทดสอบอย่างละเอียด) เพื่อทำการประมวลผลภาพโดยใช้ Synthetic Aperture Radar (SAR) เป็นวิทยาศาสตร์ / ตัวเลขในธรรมชาติ (มีรูปทรงเรขาคณิตฟิสิกส์และคณิตศาสตร์จำนวนมากที่เกี่ยวข้อง)

เคล็ดลับสองสามข้อ (สำหรับการทดสอบทางวิทยาศาสตร์ / ตัวเลขทั่วไป):

1) ใช้ผู้รุกราน อะไรคือfftของ[1,2,3,4,5]? ไม่มีความเห็น. อะไรนะifft(fft([1,2,3,4,5]))? ควรเป็น[1,2,3,4,5](หรือใกล้กับข้อผิดพลาดของจุดลอยตัวอาจเกิดขึ้น) กันไปสำหรับกรณี 2D

2) ใช้การยืนยันที่รู้จัก ถ้าคุณเขียนฟังก์ชันดีเทอร์มิแนนต์มันอาจยากที่จะบอกว่าดีเทอร์มีแนนต์คือเมทริกซ์ 100x100 แบบสุ่ม แต่คุณรู้ไหมว่าดีเทอร์มีแนนต์ของเมทริกซ์เอกลักษณ์คือ 1 แม้ว่าจะเป็น 100x100 คุณยังรู้ว่าฟังก์ชันควรส่งกลับค่า 0 บนเมทริกซ์ที่ไม่สามารถย้อนกลับได้ (เช่น 100x100 เต็มจาก 0 ทั้งหมด)

3) ใช้ asserts หยาบแทนasserts ที่แน่นอน ฉันเขียนโค้ดบางส่วนสำหรับการประมวลผล SAR ที่กล่าวว่าจะลงทะเบียนภาพสองภาพโดยการสร้างจุดผูกที่สร้างการแมประหว่างภาพแล้วทำการแปรปรวนระหว่างพวกเขาเพื่อให้ตรงกับ มันสามารถลงทะเบียนที่ระดับย่อยพิกเซล ก่อนหน้านี้มันยากที่จะพูดอะไรเกี่ยวกับการลงทะเบียนของสองภาพที่ดูเหมือน คุณจะทดสอบมันได้อย่างไร? สิ่งที่ชอบ:

EXPECT_TRUE(register(img1, img2).size() < min(img1.size(), img2.size()))

เนื่องจากคุณสามารถลงทะเบียนในส่วนที่ทับซ้อนกันเท่านั้นภาพที่ลงทะเบียนจะต้องมีขนาดเล็กกว่าหรือเท่ากับภาพที่เล็กที่สุดของคุณและด้วย:

scale = 255
EXPECT_PIXEL_EQ_WITH_TOLERANCE(reg(img, img), img, .05*scale)

เนื่องจากรูปภาพที่ลงทะเบียนไว้กับตัวเองควรจะปิดตัวเอง แต่คุณอาจพบข้อผิดพลาดเล็กน้อยเนื่องจากจุดลอยตัวเนื่องจากอัลกอริทึมในมือดังนั้นเพียงตรวจสอบแต่ละพิกเซลที่อยู่ในช่วง +/- 5% ของช่วงที่พิกเซลสามารถใช้งานได้ (0-255 เป็นสีเทาซึ่งพบได้ทั่วไปในการประมวลผลภาพ) ผลลัพธ์อย่างน้อยควรมีขนาดเท่ากับอินพุต

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

4) ใช้หรือเก็บเมล็ดแบบสุ่มสำหรับ RNG ของคุณ

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

กรณีของคุณโดยเฉพาะ

1) ทดสอบว่า ผลตอบแทนที่ว่างเปล่าtaskArray 0 (ยืนยันได้ทราบ)

2) สร้างการป้อนข้อมูลแบบสุ่มดังกล่าวว่า task.time > 0 , task.due > 0, และ task.importance > 0 สำหรับทุก taskวินาที, และยืนยันผลที่ได้คือมากกว่า (ยืนยันหยาบใส่สุ่ม)0 คุณไม่จำเป็นต้องคลั่งไคล้และสร้างเมล็ดพันธุ์แบบสุ่มอัลกอริทึมของคุณก็ไม่ซับซ้อนพอที่จะรับประกันได้ มีโอกาสประมาณ 0 ที่จะชำระเป็น: เพียงแค่ทำให้การทดสอบง่ายขึ้น

3) ทดสอบว่า task.importance == 0 สำหรับ task s ทั้งหมดหรือไม่ผลลัพท์คือ 0 (ยืนยันได้)

4) คำตอบอื่น ๆ ที่สัมผัสกับสิ่งนี้ แต่อาจเป็นเรื่องสำคัญสำหรับกรณีของคุณโดยเฉพาะ : หากคุณกำลังทำให้ผู้ใช้ที่อยู่นอกทีมของคุณต้องใช้ API คุณจะต้องทดสอบเคสที่แย่ลง ตัวอย่างเช่นหากworkPerDay == 0ตรวจสอบให้แน่ใจว่าคุณได้โยนข้อผิดพลาดที่น่ารักซึ่งบอกผู้ใช้ว่าอินพุตไม่ถูกต้อง หากคุณไม่ได้สร้าง API และเป็นเพียงสำหรับคุณและทีมงานของคุณคุณอาจข้ามขั้นตอนนี้และเพียงปฏิเสธที่จะโทรหาด้วยตัวพิมพ์เล็ก

HTH


1

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

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

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


1

บางคำตอบที่นี่ดีมาก:

  • ฐานทดสอบขอบและมุมกรณี
  • ทำการตรวจสอบสติ
  • ทำการทดสอบเปรียบเทียบ

... ฉันจะเพิ่มกลยุทธ์อื่น ๆ :

  • ย่อยสลายปัญหา
  • พิสูจน์อัลกอริทึมนอกรหัส
  • ทดสอบว่าอัลกอริทึม [พิสูจน์จากภายนอก] ได้รับการปรับใช้ตามที่ออกแบบไว้

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

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


0

นี่อาจดูเหมือนเป็นคำตอบในอุดมคติ แต่ช่วยในการระบุการทดสอบประเภทต่างๆ

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

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

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


0

ฉันคิดว่ามันเป็นที่ยอมรับอย่างสมบูรณ์ในบางโอกาสที่จะทำตามขั้นตอน:

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

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

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

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


0

คำตอบอื่น ๆ คำตอบมีเทคนิคสำหรับการทดสอบที่ดูเหมือนเมื่อไม่สามารถระบุผลลัพธ์ภายนอกฟังก์ชั่นการทดสอบได้

สิ่งที่ฉันทำนอกจากนี้ที่ฉันไม่ได้เห็นในคำตอบอื่น ๆ คือการสร้างการทดสอบอัตโนมัติในบางวิธี:

  1. อินพุตแบบสุ่ม
  2. วนซ้ำในช่วงของข้อมูล
  3. ก่อสร้างกรณีทดสอบจากชุดของขอบเขต
  4. ทั้งหมดข้างต้น

ตัวอย่างเช่นหากฟังก์ชันใช้พารามิเตอร์สามตัวแต่ละตัวที่มีช่วงอินพุตที่อนุญาต [-1,1] ให้ทดสอบชุดทั้งหมดของแต่ละพารามิเตอร์ {-2, -1.01, -1, -0.99, -0.5, -0.01, 0,0.01 , 0.5,0.99,1,1.01,2, สุ่มขึ้นใน (-1,1)}

ในระยะสั้น: บางครั้งคุณภาพที่ไม่ดีสามารถได้รับการอุดหนุนด้วยปริมาณ

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