การเขียนแบบทดสอบหน่วยสำหรับรหัสการวิจัยทางวิทยาศาสตร์ถือว่าคุ้มค่าหรือไม่


89

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

เราควรเขียนการทดสอบหน่วยสำหรับรหัสการวิจัยหรือไม่


2
นี่เป็นคำถามเปิดเล็กน้อยใช่ไหม
qubyte

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

มีบางสนทนาที่ดีในทำนองเดียวกันในเป็นคำถามใน StackOverflow
naught101

คำตอบ:


85

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

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

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

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

เปรียบเทียบและเปรียบเทียบสถานีทดลองสองแห่งที่ฉันสนับสนุน หนึ่งได้รับรอบในขณะที่และมีรหัสมรดกในขณะที่อื่น ๆ ค่อนข้างใหม่

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

ในห้องแล็บที่ใหม่กว่าฉันมักจะสามารถเพิ่มฟังก์ชั่นการใช้งานโดยการพัฒนาแบบออฟไลน์ที่โต๊ะทำงานของฉันเยาะเย้ยเฉพาะสิ่งที่จำเป็นต้องใช้ในทันทีและจากนั้นใช้เวลาสั้น ๆ ในห้องแล็บ บรรทัด

เพื่อความชัดเจนและตั้งแต่@ naught101ถาม ...

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

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


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

35

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

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

hChrrr

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

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


4
Wikipedia กล่าวว่า "การทดสอบหน่วยหรือที่เรียกว่าการทดสอบส่วนประกอบหมายถึงการทดสอบที่ตรวจสอบการทำงานของส่วนรหัสเฉพาะซึ่งมักจะอยู่ในระดับฟังก์ชั่น" การทดสอบการบรรจบกันในรหัสองค์ประกอบ จำกัด อย่างชัดเจนไม่สามารถทดสอบหน่วยตามที่เกี่ยวข้องกับฟังก์ชั่นมากมาย
David Ketcheson

นั่นคือเหตุผลที่ฉันชัดเจนที่ด้านบนของโพสต์ที่ฉันใช้มุมมองกว้างของการทดสอบหน่วยและ "มักจะ" หมายความว่า
Matt Knepley

คำถามของฉันมีความหมายในแง่ของคำจำกัดความที่เป็นที่ยอมรับมากขึ้นของการทดสอบหน่วย ตอนนี้ฉันได้ทำสิ่งนี้อย่างชัดเจนในคำถาม
David Ketcheson

ฉันได้ชี้แจงคำตอบของฉัน
Matt Knepley

ตัวอย่างหลังของคุณเกี่ยวข้องกับสิ่งที่ฉันตั้งใจ
David Ketcheson

28

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

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

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


คำถามที่เกี่ยวข้องprogrammers.stackexchange.com/questions/196362/ …
siamii

คุณจะพิจารณาการทดสอบการรวมเข้าด้วยกันหรือไม่หรือคุณคิดว่าคุณต้องเขียนการทดสอบแยกต่างหาก
siamii

ฉันจะเขียนการทดสอบหน่วยแยกต่างหากทุกที่ที่เป็นไปได้และเป็นไปได้ที่จะทำเช่นนั้น มันทำให้การดีบักง่ายขึ้นและบังคับใช้ decoupled code (ซึ่งเป็นสิ่งที่คุณต้องการ)
Geoff Oxberry

19

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

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

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


คุณมีตัวอย่างหรือเกณฑ์ที่เฉพาะเจาะจงสำหรับการเลือกชิ้นส่วนที่จะทดสอบหน่วย (และที่ไม่ได้)?
David Ketcheson

@DavidKetcheson ประสบการณ์ของฉันถูก จำกัด โดยแอปพลิเคชันและภาษาที่เราใช้ ดังนั้นสำหรับรหัส CFD วัตถุประสงค์ทั่วไปของเราที่มีประมาณ 200k บรรทัดส่วนใหญ่เป็น F90 เราได้พยายามในช่วงสองสามปีที่ผ่านมาเพื่อแยกฟังก์ชั่นบางอย่างของรหัสจริงๆ การสร้างมอดูลและการใช้มันทั่วโค้ดนั้นไม่ประสบความสำเร็จดังนั้นเราจึงต้องทำการเปรียบเทียบโมดูลเหล่านี้อย่างแท้จริงและทำให้เป็นจริงในไลบรารี ดังนั้นมีเพียงคำสั่ง USE น้อยมากและการเชื่อมต่อทั้งหมดที่มีส่วนที่เหลือของรหัสจะทำผ่านการโทรประจำ กิจวัตรประจำวันที่คุณสามารถแน่นอนได้เช่นเดียวกับส่วนที่เหลือของห้องสมุด
FrenchKeldar

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

1
ทำไมไม่รวมการทดสอบซอฟต์แวร์ประเภทอื่น ๆ (การรวมระบบ) นอกเหนือจากการทดสอบหน่วย? นอกจากเวลาและค่าใช้จ่ายแล้วนี่จะไม่ใช่วิธีแก้ปัญหาด้านเทคนิคที่สมบูรณ์แบบที่สุดใช่ไหม การอ้างอิงของฉันคือ1 (วินาที 3.4.2) และ2 (หน้า 5) กล่าวอีกนัยหนึ่งไม่ควรทดสอบซอร์สโค้ดโดยการทดสอบซอฟต์แวร์ระดับ3แบบดั้งเดิม("ระดับการทดสอบ")?
ximiki

14

การทดสอบหน่วยสำหรับรหัสทางวิทยาศาสตร์นั้นมีประโยชน์ด้วยเหตุผลหลายประการ

โดยเฉพาะอย่างยิ่งสาม:

  • การทดสอบหน่วยช่วยให้ผู้อื่นเข้าใจข้อ จำกัด ของรหัสของคุณ โดยทั่วไปการทดสอบหน่วยเป็นรูปแบบของเอกสาร

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

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

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

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

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

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


9

ในชั้นเรียน deal.II ของฉันฉันสอนซอฟแวร์ที่ไม่ได้มีการทดสอบทำงานไม่ถูกต้อง (และไปเน้นที่ฉันตั้งใจกล่าวว่า " ไม่ทำงานไม่ถูกต้อง" ไม่ " อาจไม่ทำงานอย่างถูกต้อง)

แน่นอนว่าฉันใช้ชีวิตโดยมนต์ - ซึ่งเป็นวิธีที่ดีลที่สองมาทดสอบ 2,500 ครั้งทุกการกระทำ ;-)

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


เหตุใดคุณจึงเสนอลำดับชั้นนี้ (หน่วยสำหรับระดับต่ำกว่าระดับการถดถอยที่สูงกว่า) เมื่อเทียบกับระดับดั้งเดิมในการทดสอบซอฟต์แวร์
ximiki

@ximiki - ฉันไม่ได้ตั้งใจ ฉันกำลังบอกว่าการทดสอบมีอยู่ในสเปกตรัมที่จะรวมหมวดหมู่ทั้งหมดที่ระบุไว้ในลิงก์ของคุณ
Wolfgang Bangerth

8

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


7

แน่นอน!

อะไรที่ไม่เพียงพอสำหรับคุณ

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

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


+1: "การทำงานในสเตจเช่นนี้หมายความว่าเมื่อคุณพบปัญหาคุณจะมีเฉพาะโค้ด 'สเตจ' ล่าสุดที่จะทำการทดสอบสเตจก่อนหน้านี้ได้รับการทดสอบแล้ว"
ximiki

5

ใช่.

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


3
... และจากนั้นคุณพิสูจน์ว่าหลักฐานพิสูจน์ได้ถูกต้องและ ... ตอนนี้มันเป็นหลุมกระต่ายลึก
JM

2
เต่าลงมาทำให้ Dijkstra ภูมิใจ!
aterrel

2
เพียงแค่แก้ปัญหากรณีทั่วไปจากนั้นให้พิสูจน์หลักฐานของคุณว่าถูกต้อง! พรูของเต่า!
Aesin

5

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

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


ไม่ว่าคุณจะทดสอบด้วยตนเองหรือโดยอัตโนมัติโดยใช้การทดสอบหน่วยคุณมีปัญหาเดียวกันกับการเป็นตัวแทนจุดลอยตัว ฉันอยากจะแนะนำริชาร์ดแฮร์ริสซีรีส์ยอดเยี่ยมของบทความในACCU 's นิตยสารเกินพิกัด
Mark Booth

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

5

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

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

+1: "ตรวจสอบให้แน่ใจว่าโค้ดทำงานที่ขอบและล้มเหลวอย่างงดงาม (อย่างไรก็ตามคุณกำหนดในการจำลอง) เมื่อพารามิเตอร์หรือข้อมูลป้อนเข้าอยู่นอกขอบเขตที่ยอมรับได้"
ximiki

5

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

สองเวอร์ชันแรกนั้นยุบตัวภายใต้น้ำหนักของตัวเองและการคูณของการเชื่อมโยงระหว่างกัน

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


3

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

การสร้างชุดทดสอบสำหรับรหัสต้นฉบับที่ฝังอยู่ในตัวดัดแปลงระบบเคมีขนาดใหญ่นั้นไม่สามารถทำได้ในกรอบเวลา

อย่างไรก็ตามฉันสามารถทำงานชุดตัวอย่างที่ซับซ้อนมากขึ้นซึ่งแสดงให้เห็นว่าตัวแยกวิเคราะห์ (Boost Spirit) สำหรับสูตรทางเคมีทำงานอย่างไรในขณะที่ทดสอบหน่วยสำหรับการแสดงออกที่แตกต่างกัน

การทดสอบหน่วยสุดท้ายที่ซับซ้อนที่สุดนั้นใกล้เคียงกับรหัสที่ต้องการในระบบโดยไม่จำเป็นต้องเปลี่ยนรหัสนั้นให้เป็นการเยาะเย้ย ฉันจึงสามารถคัดลอกรหัสทดสอบของหน่วย

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


2

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

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

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

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

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

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