วิธีทดสอบหน่วยนามธรรมชั้นเรียน: ขยายด้วยต้นขั้ว?


446

ฉันสงสัยว่าจะทดสอบหน่วยนามธรรมได้อย่างไรและคลาสที่ขยายคลาสนามธรรม

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

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

โปรดทราบว่าชั้นนามธรรมของฉันมีวิธีที่เป็นรูปธรรมบางอย่าง

คำตอบ:


268

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

คุณควรทดสอบคลาสนามธรรมที่มีตรรกะบางอย่างเช่นคลาสอื่น ๆ ทั้งหมดที่คุณมี


9
ประณามฉันต้องบอกว่านี่เป็นครั้งแรกที่ฉันเคยเห็นด้วยกับความคิดในการใช้จำลอง
Jonathan Allen

5
คุณต้องมีสองคลาสจำลองและทดสอบ ชั้นจำลองขยายเพียงวิธีนามธรรมของชั้นนามธรรมภายใต้การทดสอบ วิธีการเหล่านั้นอาจเป็นแบบไม่ใช้คืนค่าว่างเป็นต้นเนื่องจากจะไม่มีการทดสอบ คลาสทดสอบจะทดสอบเฉพาะ API สาธารณะที่ไม่ใช่นามธรรม (เช่นอินเตอร์เฟสที่ใช้โดยคลาสนามธรรม) สำหรับคลาสใดก็ตามที่ขยายคลาส Abstract คุณจะต้องมีคลาสทดสอบเพิ่มเติมเนื่องจากวิธีการแบบนามธรรมไม่ครอบคลุม
cyber-monk

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

5
คำตอบถัดไปที่มากเกินไปจะดีกว่ามาก
Martin Spamer

22
@MartiSpamer: ฉันจะไม่พูดคำตอบนี้มากเกินไปเพราะมันเขียนเร็วกว่ามาก (2 ปี) มากกว่าคำตอบที่คุณเห็นว่าดีกว่าด้านล่าง เราแค่สนับสนุนให้ Patrick เพราะในบริบทที่ว่าเมื่อเขาโพสต์คำตอบนี้มันเยี่ยมมาก เรามาสนับสนุนกัน ไชโย
Marvin Thobejane

449

มีสองวิธีในการใช้คลาสฐานที่เป็นนามธรรม

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

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


โซลูชันสำหรับ 1 - รูปแบบกลยุทธ์

ตัวเลือกที่ 1

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

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

IMotor

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


โซลูชันสำหรับ 2

หากคุณมีสถานการณ์ที่สองคลาสนามธรรมของคุณจะทำงานเป็นคลาสผู้ช่วย

AbstractHelper

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

ผู้ช่วยมอเตอร์

สิ่งนี้นำไปสู่คลาสที่เป็นรูปธรรมที่ง่ายและทดสอบได้ง่าย


ในฐานะที่เป็นกฎ

สนับสนุนเครือข่ายที่ซับซ้อนของวัตถุอย่างง่ายผ่านเครือข่ายที่ซับซ้อนของวัตถุที่ซับซ้อน

กุญแจสำคัญในการทดสอบรหัสที่ขยายได้คือบล็อคขนาดเล็กและการเดินสายอิสระ


อัปเดต: จะจัดการส่วนผสมของทั้งสองได้อย่างไร

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

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


อัปเดต 2: คลาสนามธรรมเป็นสเต็ปปิ้ง (2014/06/12)

ฉันมีสถานการณ์เมื่อวันก่อนที่ฉันใช้นามธรรมดังนั้นฉันต้องการสำรวจว่าทำไม

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

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

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

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

ณ จุดนี้คลาสการตั้งค่าที่พิมพ์อย่างรุนแรงจะไม่ต้องการเมธอด "getter" อีกต่อไปที่จะแสดงการใช้งาน 'การตั้งค่า'

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

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

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

ฉันคิดว่ากฎเช่นนี้กำหนดภูมิทัศน์ที่รหัสบำรุงรักษาอยู่ในหุบเขา เมื่อคุณเพิ่มพฤติกรรมใหม่มันก็เหมือนฝนตกบนโค้ดของคุณ ตอนแรกคุณวางไว้ที่ใดก็ตามที่มันตกลงมา .. จากนั้นคุณ refactor เพื่ออนุญาตให้กองกำลังของการออกแบบที่ดีที่จะผลักดันพฤติกรรมรอบ ๆ จนกว่ามันจะจบลงในหุบเขา


18
นี่คือคำตอบที่ดี ดีกว่าอันดับสูงสุด แต่ฉันเดาว่าเฉพาะผู้ที่ต้องการเขียนโค้ดที่ทดสอบได้จริง ๆเท่านั้นที่จะขอบคุณมัน :) :)
MalcomTucker

22
ฉันไม่สามารถเข้าใจได้ว่าคำตอบนี้ดีแค่ไหน มันเปลี่ยนวิธีคิดของฉันโดยสิ้นเชิงเกี่ยวกับคลาสนามธรรม ขอบคุณไนเจล
MalcomTucker

4
โอ้ไม่ .. อีกทฤษฎีที่ฉันต้องคิดใหม่! ขอบคุณ (ทั้งประชดสำหรับตอนนี้และไม่ใช่ประชดเป็นครั้งแรกที่ฉันได้หลอมรวมมันและรู้สึกเหมือนเป็นโปรแกรมเมอร์ที่ดีกว่า)
มาร์ตินน์

11
คำตอบที่ดี มีบางอย่างที่ต้องคิดเกี่ยวกับ ... แต่ไม่ใช่สิ่งที่คุณพูดโดยทั่วไปต้มลงเพื่อไม่ใช้คลาสนามธรรม?
brianestey

32
+1 สำหรับกฎเพียงอย่างเดียว "สนับสนุนเครือข่ายที่ซับซ้อนของวัตถุง่าย ๆ ผ่านเครือข่ายของวัตถุที่ซับซ้อน"
David Glass

12

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


สิ่งนี้ไม่ได้ทำให้เกิดปัญหาการส่งในคลาสย่อยหรือไม่ ถ้า X มีเมธอด a และ Y สืบทอด X แต่ก็มีเมธอด b ด้วยเช่นกัน เมื่อคุณคลาสย่อยคลาสทดสอบของคุณไม่ต้องแปลงตัวแปรนามธรรมเป็น Y เพื่อทำการทดสอบใน b
Johnno Nolan

8

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

คุณทดสอบวิธีการโดยเรียกมันเพื่อทดสอบคลาสนามธรรมโดยใช้มัน ...


8

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

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

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


6

วิธีหนึ่งคือการเขียนกรณีทดสอบนามธรรมที่สอดคล้องกับระดับนามธรรมของคุณจากนั้นเขียนกรณีทดสอบคอนกรีตที่ซับคลาสกรณีทดสอบนามธรรมของคุณ ทำสิ่งนี้ให้กับคลาสย่อยคอนกรีตที่เป็นรูปธรรมของคลาสนามธรรมดั้งเดิมของคุณ (เช่นลำดับชั้นของกรณีทดสอบของคุณจะสะท้อนลำดับชั้นของคลาสของคุณ) ดูการทดสอบอินเตอร์เฟซในหนังสือ junit recipies นี้: http://safari.informit.com/9781932394238/ch02lev1sec6

โปรดดู Testcase Superclass ในรูปแบบ xUnit: http://xunitpatterns.com/Testcase%20Superclass.html


4

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

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


ฉันไม่ต้องการทดสอบรหัสซ้ำฉันได้ทดสอบไปแล้วว่าทำไมฉันถึงต้องลงไปที่ถนนกรณีทดสอบที่เป็นนามธรรม ฉันพยายามทดสอบวิธีที่เป็นรูปธรรมทั้งหมดในชั้นนามธรรมของฉันในที่เดียว
Paul Whelan

7
ฉันไม่เห็นด้วยกับการแยกองค์ประกอบทั่วไปไปยังคลาสตัวช่วยอย่างน้อยในบางกรณี (หลายกรณี) หากคลาสนามธรรมมีฟังก์ชั่นที่เป็นรูปธรรมฉันคิดว่าเป็นที่ยอมรับอย่างสมบูรณ์ในการทดสอบหน่วยการใช้งานนั้นโดยตรง
Seth Petry-Johnson

4

นี่คือรูปแบบที่ฉันมักจะติดตามเมื่อตั้งค่าสายรัดสำหรับทดสอบคลาสนามธรรม:

public abstract class MyBase{
  /*...*/
  public abstract void VoidMethod(object param1);
  public abstract object MethodWithReturn(object param1);
  /*,,,*/
}

และรุ่นที่ฉันใช้ภายใต้การทดสอบ:

public class MyBaseHarness : MyBase{
  /*...*/
  public Action<object> VoidMethodFunction;
  public override void VoidMethod(object param1){
    VoidMethodFunction(param1);
  }
  public Func<object, object> MethodWithReturnFunction;
  public override object MethodWithReturn(object param1){
    return MethodWihtReturnFunction(param1);
  }
  /*,,,*/
}

หากวิธีนามธรรมถูกเรียกเมื่อฉันไม่ได้คาดหวังการทดสอบจะล้มเหลว เมื่อจัดเรียงการทดสอบฉันสามารถแยกวิธีการนามธรรมด้วย lambdas ที่ใช้ในการยืนยันโยนข้อยกเว้นคืนค่าต่าง ๆ ฯลฯ


3

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


2

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


2

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

จากมุมมองการทดสอบหน่วยมีสองสิ่งที่ควรพิจารณา:

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

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

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


2

ก่อนอื่นถ้าคลาส abstract มีวิธีที่เป็นรูปธรรมฉันคิดว่าคุณควรทำเช่นนี้พิจารณาตัวอย่างนี้

 public abstract class A 

 {

    public boolean method 1
    {
        // concrete method which we have to test.

    }


 }


 class B extends class A

 {

      @override
      public boolean method 1
      {
        // override same method as above.

      }


 } 


  class Test_A 

  {

    private static B b;  // reference object of the class B

    @Before
    public void init()

      {

      b = new B ();    

      }

     @Test
     public void Test_method 1

       {

       b.method 1; // use some assertion statements.

       }

   }

1

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

เพื่อหลีกเลี่ยงความสับสนในอนาคตจะทราบว่าระดับการทดสอบคอนกรีตนี้ไม่ได้เป็นเยาะเย้ย แต่ปลอม

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

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

1

ต่อไปนี้ @ patrick-desjardins คำตอบฉันใช้นามธรรมและเป็นคลาสการใช้งานพร้อมด้วย@Testดังนี้:

คลาสนามธรรม - ABC.java

import java.util.ArrayList;
import java.util.List;

public abstract class ABC {

    abstract String sayHello();

    public List<String> getList() {
        final List<String> defaultList = new ArrayList<>();
        defaultList.add("abstract class");
        return defaultList;
    }
}

เนื่องจากคลาส Abstract ไม่สามารถสร้างอินสแตนซ์ได้ แต่สามารถคลาสย่อยคลาสคอนกรีตDEF.javaจึงเป็นดังนี้:

public class DEF extends ABC {

    @Override
    public String sayHello() {
        return "Hello!";
    }
}

@Test class เพื่อทดสอบทั้ง abstract และ non-abstract method:

import org.junit.Before;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;

import org.junit.Test;

public class DEFTest {

    private DEF def;

    @Before
    public void setup() {
        def = new DEF();
    }

    @Test
    public void add(){
        String result = def.sayHello();
        assertThat(result, is(equalTo("Hello!")));
    }

    @Test
    public void getList(){
        List<String> result = def.getList();
        assertThat((Collection<String>) result, is(not(empty())));
        assertThat(result, contains("abstract class"));
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.