คุณต้องการให้สิ่งส่วนตัวภายใน / สาธารณะสำหรับการทดสอบหรือใช้การแฮ็คบางอย่างเช่น PrivateObject หรือไม่


26

ฉันค่อนข้างเริ่มต้นในการทดสอบโค้ดและเป็นassertโสเภณีก่อนหน้านี้ สิ่งหนึ่งที่ทำให้ฉันกังวลในการทดสอบหน่วยคือบ่อยครั้งที่คุณต้องสร้างฟิลด์public(หรืออย่างน้อยinternal) ที่จะเป็นprivateอย่างอื่นเพื่อยกเลิกการreadonlyสร้างprivateวิธีการprotected virtualแทน ฯลฯ

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

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


2
หลามคนมีสาธารณะเท่านั้น พวกเขามีความสุข กังวลทำไม? ทำไมไม่ทำให้ทุกอย่างเป็นสาธารณะ
S.Lott

12
เพราะมันยังห่างไกลจากแนวปฏิบัติที่ดีที่สุดในภาษาส่วนใหญ่ คำตอบที่แท้จริงคือการใช้อินเทอร์เฟซที่ดีและเพื่อให้คุณสามารถใช้วัตถุจำลองในการทดสอบ
Rig

2
@Rig: Python ไม่ใช่ภาษาอันดับต้น ๆ เหรอ? น่าสนใจ
S.Lott

7
"มันอยู่ไกลจากแนวปฏิบัติที่ดีที่สุดในภาษาหลักส่วนใหญ่" ไม่ได้บอกเป็นนัยถึงเหตุผล (หรือแม้แต่หมายถึงอย่างนั้น) "Python ไม่ใช่ภาษาอันดับต้น ๆ "
Mike Nakis

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

คำตอบ:


36

คุณไม่ควรจะต้องเคย

ทำให้public(หรืออย่างน้อยinternal) เขตข้อมูลที่จะได้รับprivateอย่างอื่นที่จะยกเลิกการreadonlyให้พวกเขาให้privateวิธีการprotected virtualแทน

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

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

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

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


2
แน่นอน! หากคุณไม่สามารถทดสอบได้โดยไม่ต้องไตร่ตรองหรือแฮ็คคุณอาจพบข้อผิดพลาดใน API หรือการออกแบบของคุณ
Falcon

คุณกำลังบอกว่าการทำprivateวิธีที่protected virtualจะช่วยในการล้อเลียนในการทดสอบนั้นถือว่าเป็นการฝึกที่ไม่ดีหรือ
Robula

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

13

ใน C # คุณสามารถใช้InternalsVisibleToAttributeเพื่อให้แอสเซมบลีการทดสอบของคุณเพื่อดูinternalคลาสในแอสเซมบลีที่คุณกำลังทดสอบ ดูเหมือนคุณจะรู้เรื่องนี้แล้ว

ในกรณีส่วนใหญ่ฉันสนใจทดสอบ API สาธารณะของแอสเซมบลีเท่านั้น ในกรณีที่ฉันต้องการทำการทดสอบกล่องขาวของบางยูนิตฉันจะย้ายรหัสไปยังinternalคลาสและทำให้เป็นpublicวิธีของคลาสนั้น จากนั้นฉันสามารถเขียนรหัสการทดสอบหน่วยสำหรับชั้นเรียนนั้น

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


8

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

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

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

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

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


6

โดยส่วนตัวฉันชอบที่จะปล่อยให้รหัสที่ฉันกำลังทดสอบบริสุทธิ์ที่สุดเท่าที่จะทำได้และถ้ารหัสทดสอบต้องแฮ็ก (และใน C ++ ตัวชี้ที่น่ารังเกียจเป็นต้น) ฉันยินดีที่จะทำเช่นนั้น



1
ฉันเห็นด้วยนี่คือวิธีที่จะทำ เก็บความอัปลักษณ์ไว้ในรหัสทดสอบที่มันไม่สามารถทำร้ายอะไร
Alan Delimon

@ AlanDelimon มันอาจไม่ทำร้ายจิตใจของโปรแกรมเมอร์บำรุงรักษาต่อไปหรือไม่
flamingpenguin

1
@flamingpenguin รหัสน่าเกลียดสามารถทำร้ายโปรแกรมเมอร์ได้ทุก แต่รหัสทดสอบที่น่าเกลียดน่าจะมีอันตรายน้อยลงเพราะมันจะส่งผลกระทบต่อคนที่ปรับเปลี่ยนคลาสเท่านั้น
Dan Neely

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

5

การมองเห็นโค้ดของคุณไม่เกี่ยวข้องกับการทดสอบหน่วยของคุณ!

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

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

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