รหัสยืนยันมากเกินไปมีกลิ่นหรือไม่


19

ฉันตกหลุมรักกับการทดสอบหน่วยและ TDD - ฉันติดเชื้อทดสอบ

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

ดังนั้นมันจึงกลายเป็นนิสัยของฉันที่ทั้งวิธีแรกและบรรทัดสุดท้ายของวิธีการส่วนตัวเป็นการยืนยัน

อย่างไรก็ตามฉันสังเกตเห็นว่าฉันมักจะใช้การยืนยันในวิธีสาธารณะ (เช่นเดียวกับส่วนตัว) เพียงแค่ "เพื่อให้แน่ใจ" นี่อาจเป็น "การทำซ้ำการทดสอบ" เนื่องจากสมมติฐานของวิธีสาธารณะได้รับการทดสอบจากภายนอกโดยกรอบการทดสอบหน่วย

ใครบางคนอาจคิดว่าการยืนยันรหัสมากเกินไปเป็นกลิ่นรหัส?


1
มีการยืนยันหรือปิดในการเปิดตัว?
jk

ฉันทำงานกับ Java เป็นหลักซึ่งต้องเปิดใช้งานการยืนยันด้วยตนเอง
Florents Tselai

เพิ่งพบสิ่งนี้ "ยืนยันเพิ่มผลผลิตโดยการติดตามข้อบกพร่อง" programmers.stackexchange.com/a/16317/32342
Florents Tselai

คุณกำหนดคำว่า "มากเกินไป" ได้อย่างไร
เฮย์เล็ม

@haylem มีคำยืนยัน "มากเกินไป" หากโปรแกรมเมอร์คนอื่นอ่านโค้ดและบอกว่า "ฉันรู้สึกเบื่อกับคำยืนยันเหล่านี้"
Florents Tselai

คำตอบ:


26

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

การทำให้พวกเขาเป็น asserts นั้นดีกว่าการใช้ความคิดเห็นเพราะพวกเขาตรวจสอบสมมติฐานอย่างแข็งขันทุกครั้งที่พวกเขาถูกเรียกใช้


2
จุดดีมาก!
Florents Tselai

1
การยืนยันเป็นเอกสาร แต่นั่นไม่ได้เป็นการทำซ้ำที่ถูกต้อง ในทางตรงกันข้ามมันยังเพิ่มความสงสัยเกี่ยวกับคุณภาพของการทดสอบหากดูเหมือนว่าจำเป็นต้องมีการยืนยันแบบเดียวกันมากกว่าหนึ่งครั้ง
Yam Marcovic

1
@ YamMarcovic ฉันคิดว่านี่เป็นสิ่งที่ยอมรับได้เพราะโค้ดทั้งสอง "ที่ซ้ำกัน" นั้นมีจุดประสงค์ที่แตกต่างกันและแตกต่างกัน ฉันคิดว่ามันมีประโยชน์ที่จะมีพวกมันทั้งสองแห่งแม้จะซ้ำซ้อน การมีการยืนยันในวิธีการนั้นเป็นสิ่งที่ประเมินค่าไม่ได้สำหรับเอกสารประกอบและจำเป็นอย่างยิ่งสำหรับการทดสอบ
Oleksi

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

15

ดูเหมือนว่าคุณกำลังพยายามทำDesign-by-Contractด้วยมือ

การทำ DbC เป็นความคิดที่ดี แต่อย่างน้อยคุณควรพิจารณาเปลี่ยนไปใช้ภาษาที่รองรับภาษาดั้งเดิม (เช่นไอเฟล ) หรืออย่างน้อยก็ใช้เฟรมเวิร์กสัญญาสำหรับแพลตฟอร์มของคุณ (เช่นMicrosoft Code Contracts for .NETเป็นสิ่งที่ค่อนข้างดีโครงร่างสัญญาที่มีความซับซ้อนมากที่สุดนั้นมีประสิทธิภาพยิ่งกว่าหอไอเฟล) ด้วยวิธีนี้คุณสามารถใช้ประโยชน์จากพลังของสัญญาได้ดีขึ้น เช่นการใช้เฟรมเวิร์กที่มีอยู่คุณสามารถทำสัญญาในเอกสารของคุณหรือ IDE (เช่น Code Contracts สำหรับ. NET จะแสดงใน IntelliSense และหากคุณมี VS Ultimate คุณสามารถตรวจสอบแบบคงที่ได้โดยทฤษฎีบทอัตโนมัติในเวลารวบรวม คุณพิมพ์เช่นเดียวกันกรอบงานสัญญา Java จำนวนมากมีเอกสารกำกับ JavaDoc ที่จะแยกสัญญาออกเป็นเอกสาร JavaDoc API ของคุณโดยอัตโนมัติ)

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

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


4

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

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

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

ส่วนตัวฉันไม่ชอบassertคำสั่งใน Java เนื่องจากพวกเขาสามารถปิดและมันก็เป็นความปลอดภัยที่ผิดพลาด


1
+1 สำหรับ "ฉันไม่ชอบคำสั่ง assert ใน Java เนื่องจากสามารถปิดได้แล้วจึงเป็นความปลอดภัยที่ผิดพลาด"
Florents Tselai

3

ฉันคิดว่าการใช้การยืนยันในวิธีสาธารณะนั้นสำคัญกว่าเพราะคุณไม่ได้ควบคุมอินพุตและอาจมีข้อสันนิษฐานที่แตก

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

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

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


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

การยืนยันสามารถ (และในหลายกรณีควร) รวมถึงการบันทึกและการโยนข้อยกเว้น (หรือรหัสข้อผิดพลาดใน C -)
Danny Varod

3

มันยากที่จะเป็นผู้ไม่เชื่อเรื่องพระเจ้าเกี่ยวกับปัญหานี้เนื่องจากรายละเอียดของวิธีการยืนยันและการจัดการข้อผิดพลาด / ข้อยกเว้นที่เหมาะสมถูกนำมาใช้ในการตอบคำถาม นี่คือ $ 0.02 ของฉันตามความรู้ของฉันเกี่ยวกับ Java & C ++

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

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

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


2

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

ไม่ใช่โปรแกรมเมอร์ทุกคนที่สมบูรณ์แบบ - อีกครั้งการอ้างถึงหมายความว่าหนึ่งใน "สลิปอัพ" เหล่านั้นจะไม่เผยแพร่ไกลเกินไป

อย่าดูถูกดูแคลนผลยืนยันเหล่านี้ (และการตรวจสอบอื่น ๆ เกี่ยวกับสมมติฐาน) จะมีในการลดต้นทุนการบำรุงรักษา


0

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

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

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

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


0

อย่างไรก็ตามการทดสอบหน่วยจะใช้สำหรับวิธีการสาธารณะ

หากกรอบการทดสอบของคุณอนุญาตสำหรับ accessors ดังนั้นการทดสอบหน่วยวิธีส่วนตัวก็เป็นความคิดที่ดี (IMO)

ใครบางคนอาจคิดว่าการยืนยันรหัสมากเกินไปเป็นกลิ่นรหัส?

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


-2

มันเป็นการฝึกฝนที่ไม่ดี

คุณไม่ควรทดสอบวิธีสาธารณะ / ส่วนตัว คุณควรทดสอบคลาสโดยรวม เพียงให้แน่ใจว่าคุณมีความคุ้มครองที่ดี

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

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

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


-1 การทดสอบหน่วยการเรียนโดยรวมอาจเป็นอันตรายได้เนื่องจากคุณสิ้นสุดการทดสอบมากกว่าหนึ่งอย่างต่อการทดสอบ ทำให้การทดสอบที่เปราะบางจริงๆ คุณควรทดสอบพฤติกรรมหนึ่งอย่างในคราวเดียวซึ่งมักจะสอดคล้องกับการทดสอบเพียงวิธีเดียวต่อการทดสอบ
Oleksi

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

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